之前在RSA PKCS1和PKCS8的ASN格式一文里,我们已经分析过了PKCS1和PKCS8格式的密钥了
那么,我们现在就做一个c#通用的解析代码,即能解析PKCS1的密钥,也能解析PKCS8的密钥
public static partial class Encryption
{
public static class AsnParser
{
public static RSAParameters ParseRSAPrivateKey(byte[] bt)
{
RSAParameters rsap = new RSAParameters();
// Initial value
List<byte> octets = new List<byte>();
octets.AddRange(bt);
int initialCount = bt.Length;
// Current value
byte[] value = null;
// Checkpoint
int position = CurrentPosition(initialCount, octets);
// Sanity Check
int length = 0;
byte b = 0;
length = NextSequence(ref initialCount, ref octets, out b);
if (length != RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Sequence Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture), RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Version
value = NextInteger(ref initialCount, ref octets);
if (0x00 != value[0])
{
StringBuilder sb = new StringBuilder("Incorrect PrivateKeyInfo Version. ");
BigInteger v = new BigInteger(value);
sb.AppendFormat("Expected: 0, Specified: {0}", v.ToString(10));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Ignore Sequence - AlgorithmIdentifier
length = NextSequence(ref initialCount, ref octets, out b);
if (0x30 == b) // PKCS8
{
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect AlgorithmIdentifier Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Grab the OID
value = NextOID(ref initialCount, ref octets);
byte[] oid = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
if (!EqualOid(value, oid))
{
//throw new BerDecodeException("Expected OID 1.2.840.113549.1.1.1", position);
throw new Exception("Expected OID 1.2.840.113549.1.1.1");
}
// Optional Parameters
if (IsNextNull(octets))
{
NextNull(ref initialCount, ref octets);
// Also OK: value = parser.Next();
}
else
{
// Gracefully skip the optional data
value = Next(ref initialCount, ref octets);
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Ignore OctetString - PrivateKey
length = NextOctetString(ref initialCount, ref octets);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect PrivateKey Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Ignore Sequence - RSAPrivateKey
length = NextSequence(ref initialCount, ref octets, out b);
if (length < RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect RSAPrivateKey Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Version
value = NextInteger(ref initialCount, ref octets);
if (0x00 != value[0])
{
StringBuilder sb = new StringBuilder("Incorrect RSAPrivateKey Version. ");
BigInteger v = new BigInteger(value);
sb.AppendFormat("Expected: 0, Specified: {0}", v.ToString(10));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
rsap.Modulus = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.Exponent = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.D = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.P = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.Q = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.DP = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.DQ = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.InverseQ = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
}
if (0x02 == b) // PKCS1
{
rsap.Modulus = TrimLeadingZero(GetOctets(ref initialCount, ref octets, length));
rsap.Exponent = TrimLeadingZero(GetOctets(ref initialCount, ref octets, NextSequence(ref initialCount, ref octets, out b)));
rsap.D = TrimLeadingZero(GetOctets(ref initialCount, ref octets, NextSequence(ref initialCount, ref octets, out b)));
rsap.P = TrimLeadingZero(GetOctets(ref initialCount, ref octets, NextSequence(ref initialCount, ref octets, out b)));
rsap.Q = TrimLeadingZero(GetOctets(ref initialCount, ref octets, NextSequence(ref initialCount, ref octets, out b)));
rsap.DP = TrimLeadingZero(GetOctets(ref initialCount, ref octets, NextSequence(ref initialCount, ref octets, out b)));
rsap.DQ = TrimLeadingZero(GetOctets(ref initialCount, ref octets, NextSequence(ref initialCount, ref octets, out b)));
rsap.InverseQ = TrimLeadingZero(GetOctets(ref initialCount, ref octets, NextSequence(ref initialCount, ref octets, out b)));
}
return rsap;
}
public static RSAParameters ParseRSAPublicKey(byte[] bt)
{
RSAParameters rsap = new RSAParameters();
// Initial value
List<byte> octets = new List<byte>();
octets.AddRange(bt);
int initialCount = bt.Length;
byte b = 0;
// Current value
byte[] value = null;
// Sanity Check
int length = 0;
// Checkpoint
int position = CurrentPosition(initialCount, octets);
// Ignore Sequence - PublicKeyInfo
length = NextSequence(ref initialCount, ref octets, out b);
if (length != RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Sequence Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Ignore Sequence - AlgorithmIdentifier
length = NextSequence(ref initialCount, ref octets, out b);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect AlgorithmIdentifier Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Grab the OID
value = NextOID(ref initialCount, ref octets);
byte[] oid = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
if (!EqualOid(value, oid))
{
//throw new BerDecodeException("Expected OID 1.2.840.113549.1.1.1", position);
throw new Exception("Expected OID 1.2.840.113549.1.1.1");
}
// Optional Parameters
if (IsNextNull(octets))
{
NextNull(ref initialCount, ref octets);
// Also OK: value = parser.Next();
}
else
{
// Gracefully skip the optional data
value = Next(ref initialCount, ref octets);
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Ignore BitString - PublicKey
length = NextBitString(ref initialCount, ref octets);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect PublicKey Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
(RemainingBytes(octets)).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Checkpoint
position = CurrentPosition(initialCount, octets);
// Ignore Sequence - RSAPublicKey
length = NextSequence(ref initialCount, ref octets, out b);
if (length < RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect RSAPublicKey Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
rsap.Modulus = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
rsap.Exponent = TrimLeadingZero(NextInteger(ref initialCount, ref octets));
return rsap;
}
public static byte[] ExportRSAPrivateKey(RSAParameters rp, RSA.PaddingType padding)
{
int count = 0;
List<byte[]> bytes = new List<byte[]>();
bytes.Add(rp.InverseQ);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 129, 128 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.DQ);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 129, 128 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.DP);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 129, 128 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.Q);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 129, 128 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.P);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 129, 128 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.D);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 130, 1, 0 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.Exponent);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 3 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.Modulus);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 130, 1, 0 });
count += bytes[bytes.Count - 1].Length;
switch (padding)
{
case RSA.PaddingType.PKCS1:
break;
case RSA.PaddingType.PKCS8:
bytes.Add(new byte[] { 2, 1, 0 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(IntToByte(count));
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 48, 130 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(IntToByte(count));
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130 });
count += bytes[bytes.Count - 1].Length;
break;
default:
throw new Exception("Invalid RSA PaddingType");
}
bytes.Add(new byte[] { 2, 1, 0 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(IntToByte(count));
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 48, 130 });
count += bytes[bytes.Count - 1].Length;
byte[] result = new byte[count];
int cur = 0;
for (var i = 0; i < bytes.Count; i++)
{
Array.Copy(bytes[i], 0, result, count - bytes[i].Length - cur, bytes[i].Length);
cur += bytes[i].Length;
}
return result;
}
public static byte[] ExportRSAPublicKey(RSAParameters rp)
{
int count = 0;
List<byte[]> bytes = new List<byte[]>();
bytes.Add(rp.Exponent);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 3 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(rp.Modulus);
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 2, 130, 1, 1, 0 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(IntToByte(count));
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 48, 130 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 0 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(IntToByte(count));
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130 });
count += bytes[bytes.Count - 1].Length;
bytes.Add(IntToByte(count));
count += bytes[bytes.Count - 1].Length;
bytes.Add(new byte[] { 48, 130 });
count += bytes[bytes.Count - 1].Length;
byte[] result = new byte[count];
int cur = 0;
for (var i = 0; i < bytes.Count; i++)
{
Array.Copy(bytes[i], 0, result, count - bytes[i].Length - cur, bytes[i].Length);
cur += bytes[i].Length;
}
return result;
}
private static byte[] IntToByte(int i)
{
if (i < 256)
{
return new byte[] { (byte)i };
}
string h = i.ToString("x");
MatchCollection mc = RegexExpand.Matches(h, @"[a-f0-9]{1,2}(?=([a-f0-9]{2})*$)", RegexOptions.IgnoreCase);
List<byte> result = new List<byte>();
for (int ii = 0; ii < mc.Count; ii++)
{
result.Add((byte)Convert.ToInt16(mc[ii].Value, 16));
}
return result.ToArray();
}
private static byte[] TrimLeadingZero(byte[] values)
{
byte[] r = null;
if ((0x00 == values[0]) && (values.Length > 1))
{
r = new byte[values.Length - 1];
Array.Copy(values, 1, r, 0, values.Length - 1);
}
else
{
r = new byte[values.Length];
Array.Copy(values, r, values.Length);
}
return r;
}
private static int NextBitString(ref int initialCount, ref List<byte> octets)
{
int position = CurrentPosition(initialCount, octets);
try
{
byte b = GetNextOctet(ref initialCount, ref octets);
if (0x03 != b)
{
StringBuilder sb = new StringBuilder("Expected Bit String. ");
sb.AppendFormat("Specified Identifier: {0}", b.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
int length = GetLength(ref initialCount, ref octets);
// We need to consume unused bits, which is the first
// octet of the remaing values
b = octets[0];
octets.RemoveAt(0);
length--;
if (0x00 != b)
{
//throw new BerDecodeException("The first octet of BitString must be 0", position);
throw new Exception("The first octet of BitString must be 0");
}
return length;
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
}
private static int NextOctetString(ref int initialCount, ref List<byte> octets)
{
int position = CurrentPosition(initialCount, octets);
try
{
byte b = GetNextOctet(ref initialCount, ref octets);
if (0x04 != b)
{
StringBuilder sb = new StringBuilder("Expected Octet String. ");
sb.AppendFormat("Specified Identifier: {0}", b.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
int length = GetLength(ref initialCount, ref octets);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Octet String Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
return length;
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
}
private static byte[] Next(ref int initialCount, ref List<byte> octets)
{
int position = CurrentPosition(initialCount, octets);
try
{
byte b = GetNextOctet(ref initialCount, ref octets);
int length = GetLength(ref initialCount, ref octets);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
return GetOctets(ref initialCount, ref octets, length);
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
}
private static int NextNull(ref int initialCount, ref List<byte> octets)
{
int position = CurrentPosition(initialCount, octets);
try
{
byte b = GetNextOctet(ref initialCount, ref octets);
if (0x05 != b)
{
StringBuilder sb = new StringBuilder("Expected Null. ");
sb.AppendFormat("Specified Identifier: {0}", b.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
// Next octet must be 0
b = GetNextOctet(ref initialCount, ref octets);
if (0x00 != b)
{
StringBuilder sb = new StringBuilder("Null has non-zero size. ");
sb.AppendFormat("Size: {0}", b.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
return 0;
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
}
private static bool IsNextNull(List<byte> octets)
{
return 0x05 == octets[0];
}
private static bool EqualOid(byte[] first, byte[] second)
{
if (first.Length != second.Length) { return false; }
for (int i = 0; i < first.Length; i++)
{
if (first[i] != second[i]) { return false; }
}
return true;
}
private static byte[] NextOID(ref int initialCount, ref List<byte> octets)
{
int position = CurrentPosition(initialCount, octets);
try
{
byte b = GetNextOctet(ref initialCount, ref octets);
if (0x06 != b)
{
StringBuilder sb = new StringBuilder("Expected Object Identifier. ");
sb.AppendFormat("Specified Identifier: {0}",
b.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
int length = GetLength(ref initialCount, ref octets);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Object Identifier Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
byte[] values = new byte[length];
for (int i = 0; i < length; i++)
{
values[i] = octets[0];
octets.RemoveAt(0);
}
return values;
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
}
private static byte[] NextInteger(ref int initialCount, ref List<byte> octets)
{
int position = CurrentPosition(initialCount, octets);
try
{
byte b = GetNextOctet(ref initialCount, ref octets);
if (0x02 != b)
{
StringBuilder sb = new StringBuilder("Expected Integer. ");
sb.AppendFormat("Specified Identifier: {0}", b.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
int length = GetLength(ref initialCount, ref octets);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Integer Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
return GetOctets(ref initialCount, ref octets, length);
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
}
private static int CurrentPosition(int initialCount, List<byte> octets)
{
return initialCount - octets.Count;
}
private static int RemainingBytes(List<byte> octets)
{
return octets.Count;
}
private static byte[] GetOctets(ref int initialCount, ref List<byte> octets, int octetCount)
{
int position = CurrentPosition(initialCount, octets);
if (octetCount > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
octetCount.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
byte[] values = new byte[octetCount];
try
{
octets.CopyTo(0, values, 0, octetCount);
octets.RemoveRange(0, octetCount);
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
return values;
}
private static byte GetNextOctet(ref int initialCount, ref List<byte> octets)
{
int position = CurrentPosition(initialCount, octets);
if (0 == RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
1.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
byte b = GetOctets(ref initialCount, ref octets, 1)[0];
return b;
}
private static int GetLength(ref int initialCount, ref List<byte> octets)
{
int length = 0;
// Checkpoint
int position = CurrentPosition(initialCount, octets);
try
{
byte b = GetNextOctet(ref initialCount, ref octets);
if (b == (b & 0x7f)) { return b; }
int i = b & 0x7f;
if (i > 4)
{
StringBuilder sb = new StringBuilder("Invalid Length Encoding. ");
sb.AppendFormat("Length uses {0} octets",
i.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
while (0 != i--)
{
// shift left
length <<= 8;
length |= GetNextOctet(ref initialCount, ref octets);
}
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
return length;
}
private static int NextSequence(ref int initialCount, ref List<byte> octets, out byte b)
{
int position = CurrentPosition(initialCount, octets);
try
{
b = GetNextOctet(ref initialCount, ref octets);
int length = 0;
if (0x30 == b) // PKCS8
{
length = GetLength(ref initialCount, ref octets);
if (length > RemainingBytes(octets))
{
StringBuilder sb = new StringBuilder("Incorrect Sequence Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
RemainingBytes(octets).ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
}
if (0x02 == b) // PKCS1
{
byte x = GetOctets(ref initialCount, ref octets, 1)[0];
if (x == 0x81)
{
length = GetOctets(ref initialCount, ref octets, 1)[0];
}
else if (x == 0x82)
{
byte h = GetOctets(ref initialCount, ref octets, 1)[0];
byte l = GetOctets(ref initialCount, ref octets, 1)[0];
byte[] m = { l, h, 0x00, 0x00 };
length = BitConverter.ToInt32(m, 0);
//length = h<<8|l;
}
else
{
length = x;
}
while (octets[0] == 0x00)
{
GetOctets(ref initialCount, ref octets, 1);
length--;
}
}
if (length == 0)
{
StringBuilder sb = new StringBuilder("Expected Sequence. ");
sb.AppendFormat("Specified Identifier: {0}",
b.ToString(CultureInfo.InvariantCulture));
//throw new BerDecodeException(sb.ToString(), position);
throw new Exception(sb.ToString());
}
return length;
}
catch (ArgumentOutOfRangeException ex)
{
//throw new BerDecodeException("Error Parsing Key", position, ex);
throw ex;
}
}
}
}
调用方法也很简单
string base64 = FileHelper.FileToString(fi.FullName);
if (Regex.IsMatch(base64, @"^[-]+BEGIN"))
{
base64 = Regex.Match(base64, @"(?<=KEY[-]+[\r\n]+)[\s\S]+(?=[\r\n]+[-]+END)").Value;
base64 = Regex.Replace(base64, @"[\r\n]+", "");
}
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(8);
rsa.ImportParameters(AsnParser.ParseRSAPrivateKey(Convert.FromBase64String(base64)));
直接从密钥文件中得到的密钥数据,掐头去尾,把回车换行去掉之后转个码,然后用AsnParser解析成RSAParameters对象,直接导入
至于PKCS1和PKCS8的区别,则在AsnParser的NextSequence方法中有体现,第八个字节为48,即0x30时,为PKCS8格式,如果第八个字节为2,即0x02时,则为PKCS1,为其他值时,则为验证数据