什么等效于C#

时间:2018-09-19 13:14:27

标签: c# .net encryption jwt x509certificate2

我正在尝试将一段Java代码移植到.NET中,该代码采用Base64编码的字符串,将其转换为字节数组,然后使用其制作X.509证书以获取RSA的模数和指数加密。 这是我要转换的Java代码:

byte[] externalPublicKey = Base64.decode("base 64 encoded string");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(externalPublicKey);
Key publicKey = keyFactory.generatePublic(publicKeySpec);
RSAPublicKey pbrtk = (java.security.interfaces.RSAPublicKey) publicKey;
BigInteger modulus = pbrtk.getModulus();
BigInteger pubExp = pbrtk.getPublicExponent();

我一直在尝试找出将其转换为.NET的最佳方法。到目前为止,我已经提出了这个建议:

byte[] bytes = Convert.FromBase64String("base 64 encoded string");
X509Certificate2 x509 = new X509Certificate2(bytes);
RSA rsa = (RSA)x509.PrivateKey;
RSAParameters rsaParams = rsa.ExportParameters(false);
byte[] modulus = rsaParams.Modulus;
byte[] exponent = rsaParams.Exponent;

在我看来这应该可以工作,但是当我使用Java代码中以base 64编码的字符串生成X509证书时,它将引发CryptographicException。我收到的确切消息是:

找不到请求的对象。

Java的X.509实现只是与.NET不兼容,还是我从Java转换为.NET时做错了什么?

2 个答案:

答案 0 :(得分:0)

在.NET Core 3.0及更高版本中,有一种ImportSubjectPublicKeyInfo方法可以直接导入此类密钥。

代码如下:

var bytes = Convert.FromBase64String("encoded key");
var rsa = RSA.Create();
rsa.ImportSubjectPublicKeyInfo(bytes, out _);
var rsaParams = rsa.ExportParameters(false);

答案 1 :(得分:-1)

例如

            var subjectPublicKeyInfo = new SubjectPublicKeyInfo(your bytes);
            var publicKey = subjectPublicKeyInfo.GetPublicKey();

            using (var rsa = new RSACryptoServiceProvider())
            {
                RSAParameters parameters = new RSAParameters()
                {
                    Modulus = publicKey.Item1,
                    Exponent = publicKey.Item2
                };
                rsa.ImportParameters(parameters);
                /*
                do something
                */
            }

SubjectPublicKeyInfo类和DER


        /// <summary>
        /// DER解析
        /// </summary>
        public class DER : IDisposable
        {
            private bool disposedValue;
            private BinaryReader reader;

            public DER(byte[] bytes)
            {
                MemoryStream stream = new MemoryStream(bytes);
                reader = new BinaryReader(stream);
            }

            public bool CanRead => reader.BaseStream.Position < reader.BaseStream.Length;

            private ValueType ReadType()
            {
                return (ValueType)reader.ReadByte();
            }

            private int ReadLength()
            {
                int length = reader.ReadByte();

                //检查第7位是否是1,如果是,则指示该内容长度大于127字节,则此字节6-0为实际的内容占用的字节
                if ((length & 0b10000000) == 0b10000000)
                {
                    //获取长度字节的长度
                    int count = length & 0b01111111;
                    byte[] bytes = new byte[count];

                    //指向内容的长度
                    reader.Read(bytes, 0, bytes.Length);

                    //翻转顺序
                    Array.Reverse(bytes);
                    length = LengthBytesToInt(bytes);
                }

                return length;
            }

            /// <summary>
            /// 根据文档显示,长度不应该超过 256^126 ,即两个字节
            /// </summary>
            /// <param name="lengthBytes"></param>
            /// <returns></returns>
            private int LengthBytesToInt(byte[] lengthBytes)
            {
                if (lengthBytes.Length > 2)
                    throw new ArgumentOutOfRangeException($"length {lengthBytes.Length} too big.");
                int value = 0;
                for (int i = 0; i < lengthBytes.Length; i++)
                {
                    value = (value << 8) | lengthBytes[i];
                }
                return value;
            }

            public ValueTuple<ValueType, byte[]> ReadValue()
            {
                ValueType type = ReadType();
                byte[] value = new byte[ReadLength()];
                reader.Read(value, 0, value.Length);
                ValueTuple<ValueType, byte[]> wrapper = new ValueTuple<ValueType, byte[]>(type, value);
                return wrapper;
            }

            public enum ValueType
            {
                BOOLEAN = 0x01,
                INTEGER = 0x02,
                BIT_STRING = 0x03,
                OCTET_STRING = 0x04,
                NULL = 0x05,
                OBJECT_IDENTIFIER = 0x06,
                UTF8String = 0x0c,
                PrintableString = 0x13,
                TeletexString = 0x14,
                IA5String = 0x16,
                BMPString = 0x1e,
                SEQUENCE = 0x30,
                SET = 0x31
            }

            protected virtual void Dispose(bool disposing)
            {
                if (!disposedValue)
                {
                    if (disposing)
                    {
                        reader.Dispose();
                    }
                    disposedValue = true;
                }
            }

            public void Dispose()
            {
                Dispose(disposing: true);
                GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// 兼容 Java X.509 SubjectPublicKeyInfo DER
        /// </summary>
        public class SubjectPublicKeyInfo
        {
            private DER der;
            private readonly byte[] RSA_OID = new byte[] { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };

            public SubjectPublicKeyInfo(byte[] derBytes)
            {
                der = new DER(derBytes);
            } 

            /// <summary>
            /// 获取公钥
            /// </summary>
            /// <returns>modulus and exponent 返回模数和指数</returns>
            public ValueTuple<byte[], byte[]> GetPublicKey()
            {
                //获取主序列
                var wrapper1 = der.ReadValue();
                if (wrapper1.Item1 != DER.ValueType.SEQUENCE)
                {
                    throw new InvalidDataException();
                }
                var sequence1 = new DER(wrapper1.Item2);
                var wrapper2 = sequence1.ReadValue();

                //检查第一个结构体是否存在
                if (wrapper2.Item1 != DER.ValueType.SEQUENCE)
                {
                    throw new InvalidDataException();
                }

                var sequence2 = new DER(wrapper2.Item2);
                var wrapper3 = sequence2.ReadValue();
                if (wrapper3.Item1 != DER.ValueType.OBJECT_IDENTIFIER)
                {
                    throw new InvalidDataException();
                }

                if (Enumerable.SequenceEqual(wrapper3.Item2, RSA_OID) == false)
                {
                    throw new InvalidDataException();
                }

                var wrapper4 = sequence1.ReadValue();
                if (wrapper4.Item2.First() != 0x00)
                {
                    throw new InvalidDataException();
                }

                //这里有个不明意义的0x00
                var sequence3 = new DER(wrapper4.Item2.Skip(1).ToArray());
                var wrapper5 = sequence3.ReadValue();
                if (wrapper5.Item1 != DER.ValueType.SEQUENCE)
                {
                    throw new InvalidDataException();
                }

                var sequence4 = new DER(wrapper5.Item2);
                var wrapper6 = sequence4.ReadValue();
                if (wrapper6.Item1 != DER.ValueType.INTEGER)
                {
                    throw new InvalidDataException();
                }
                var integer1 = wrapper6.Item2.First() == 0x00 ? wrapper6.Item2.Skip(1).ToArray() : wrapper6.Item2;

                var wrapper7 = sequence4.ReadValue();
                if (wrapper7.Item1 != DER.ValueType.INTEGER)
                {
                    throw new InvalidDataException();
                }

                var integer2 = wrapper7.Item2;

                return new ValueTuple<byte[], byte[]>(integer1, integer2);
            }
        }