/// <summary> /// Writes the core. /// </summary> /// <param name="stream">The stream.</param> /// <param name="value">The value.</param> protected override void WriteCore(Stream stream, RSAParameters value) { Requires.NotNull(stream, nameof(stream)); using var sequence = new MemoryStream(); if (KeyFormatter.HasPrivateKey(value)) { // Only include the version element if this is a private key. sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, new byte[1])); } // Take care to always prepend a zero when an integer starts with a leading bit of 1, // since the ASN.1 spec is that integers are encoded as two's complement, and these integers // are always intended to be interpreted as positive. sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.Modulus !))); sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.Exponent !))); if (KeyFormatter.HasPrivateKey(value)) { sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.D !))); sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.P !))); sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.Q !))); sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.DP !))); sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.DQ !))); sequence.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, PrependLeadingZero(value.InverseQ !))); } stream.WriteAsn1Element(new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.Sequence, sequence.ToArray())); }
/// <summary> /// Reads a key from the specified stream. /// </summary> /// <param name="stream">The stream.</param> /// <returns> /// The RSA Parameters of the key. /// </returns> /// <exception cref="System.ArgumentException"> /// Unexpected format. /// or /// Unexpected format. /// or /// Unexpected algorithm. /// or /// Unexpected format. /// </exception> protected override RSAParameters ReadCore(Stream stream) { var sequence = stream.ReadAsn1Elements().First(); if (sequence.Class != Asn.BerClass.Universal || sequence.PC != Asn.BerPC.Constructed || sequence.Tag != Asn.BerTag.Sequence) { throw new ArgumentException("Unexpected format."); } var elements = Asn.ReadAsn1Elements(sequence.Content).ToList(); if (elements.Count != 2 || elements[0].Class != Asn.BerClass.Universal || elements[0].PC != Asn.BerPC.Constructed || elements[0].Tag != Asn.BerTag.Sequence) { throw new ArgumentException("Unexpected format."); } var oid = Asn.ReadAsn1Elements(elements[0].Content).First(); if (!KeyFormatter.BufferEqual(Pkcs1KeyFormatter.RsaEncryptionObjectIdentifier, oid.Content)) { throw new ArgumentException("Unexpected algorithm."); } if (elements[1].Class != Asn.BerClass.Universal || elements[1].PC != Asn.BerPC.Primitive || elements[1].Tag != Asn.BerTag.BitString || elements[1].Content[0] != 0) { throw new ArgumentException("Unexpected format."); } byte[] rsaPublicKey = TrimLeadingZero(elements[1].Content); return(KeyFormatter.PublicKeyFilter(KeyFormatter.Pkcs1.Read(rsaPublicKey))); }
/// <summary> /// Reads a key from the specified stream. /// </summary> /// <param name="stream">The stream.</param> /// <returns> /// The RSA Parameters of the key. /// </returns> protected override RSAParameters ReadCore(Stream stream) { var universalConstructedSequence = stream.ReadAsn1Elements().Single(); var sequence = Asn.ReadAsn1Elements(universalConstructedSequence.Content).ToList(); KeyFormatter.VerifyFormat(sequence[0].Content.Length == 1 && sequence[0].Content[0] == 0x00, Strings.UnrecognizedVersion); Asn.DataElement oid = Asn.ReadAsn1Elements(sequence[1].Content).First(); KeyFormatter.VerifyFormat(X509SubjectPublicKeyInfoFormatter.BufferEqual(oid.Content, Pkcs1KeyFormatter.RsaEncryptionObjectIdentifier), Strings.UnrecognizedObjectIdentifier); return(KeyFormatter.Pkcs1.Read(sequence[2].Content)); }
/// <summary> /// Writes a key to the specified stream. /// </summary> /// <param name="stream">The stream.</param> /// <param name="parameters">The RSA parameters of the key.</param> protected override void WriteCore(Stream stream, RSAParameters parameters) { var rootElement = new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.Sequence, new Asn.DataElement( // Version 0 Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, new byte[] { 0x00 }), new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.Sequence, new Asn.DataElement( // privateKeyAlgorithm Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.ObjectIdentifier, Pkcs1KeyFormatter.RsaEncryptionObjectIdentifier), new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Null, new byte[0])), new Asn.DataElement( // rsaPrivateKey Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.OctetString, KeyFormatter.Pkcs1PrependZeros.Write(parameters, HasPrivateKey(parameters))), new Asn.DataElement( Asn.BerClass.ContextSpecific, Asn.BerPC.Constructed, Asn.BerTag.EndOfContent, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.Sequence, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.ObjectIdentifier, new byte[] { 0x55, 0x1d, 0x0f }), new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.SetAndSetOf, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.BitString, new byte[] { 0x00, 0x10 }))))); Asn.WriteAsn1Element(stream, rootElement); }
/// <summary> /// Writes a key to the specified stream. /// </summary> /// <param name="stream">The stream.</param> /// <param name="parameters">The RSA parameters of the key.</param> protected override void WriteCore(Stream stream, RSAParameters parameters) { var version0 = new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Integer, new byte[] { 0x00 }); var privateKeyAlgorithm = new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.ObjectIdentifier, RsaEncryptionObjectIdentifier); var rsaPrivateKey = new Asn.DataElement(Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.OctetString, Pkcs1.Write(parameters, HasPrivateKey(parameters))); var rootElement = new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.Sequence, version0, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.Sequence, privateKeyAlgorithm, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.Null, Array.Empty <byte>())), rsaPrivateKey, new Asn.DataElement( Asn.BerClass.ContextSpecific, Asn.BerPC.Constructed, Asn.BerTag.EndOfContent, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.Sequence, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.ObjectIdentifier, new byte[] { 0x55, 0x1d, 0x0f }), new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Constructed, Asn.BerTag.SetAndSetOf, new Asn.DataElement( Asn.BerClass.Universal, Asn.BerPC.Primitive, Asn.BerTag.BitString, new byte[] { 0x00, 0x10 }))))); Asn.WriteAsn1Element(stream, rootElement); }
/// <summary> /// Reads a key from the specified stream. /// </summary> /// <param name="stream">The stream.</param> /// <returns> /// The RSA Parameters of the key. /// </returns> protected override RSAParameters ReadCore(Stream stream) { var keyBlobElement = Asn.ReadAsn1Elements(stream).First(); KeyFormatter.VerifyFormat( keyBlobElement.Class == Asn.BerClass.Universal && keyBlobElement.PC == Asn.BerPC.Constructed && keyBlobElement.Tag == Asn.BerTag.Sequence); stream = new MemoryStream(keyBlobElement.Content); var sequence = Asn.ReadAsn1Elements(stream).ToList(); switch (sequence.Count) { case 2: return(new RSAParameters { Modulus = sequence[0].Content, Exponent = sequence[1].Content, }); case 9: KeyFormatter.VerifyFormat(sequence[0].Content.Length == 1 && sequence[0].Content[0] == 0, "Unsupported version."); return(new RSAParameters { Modulus = sequence[1].Content, Exponent = sequence[2].Content, D = sequence[3].Content, P = sequence[4].Content, Q = sequence[5].Content, DP = sequence[6].Content, DQ = sequence[7].Content, InverseQ = sequence[8].Content, }); default: throw KeyFormatter.FailFormat(); } }
/// <summary> /// Initializes a new instance of the <see cref="DataElement"/> struct. /// </summary> /// <param name="class">The class.</param> /// <param name="pc">The PC.</param> /// <param name="tag">The tag.</param> /// <param name="nestedElements">The content.</param> public DataElement(BerClass @class, BerPC pc, BerTag tag, params DataElement[] nestedElements) : this(@class, pc, tag, Asn.WriteAsn1Elements(nestedElements)) { }