/// <summary> /// Reads the next value as a Integer with a specified tag, returning the contents /// as a <see cref="BigInteger"/> over the original data. /// </summary> /// <param name="expectedTag">The tag to check for before reading.</param> /// <returns> /// The bytes of the Integer value, in signed big-endian form. /// </returns> /// <exception cref="CryptographicException"> /// the next value does not have the correct tag --OR-- /// the length encoding is not valid under the current encoding rules --OR-- /// the contents are not valid under the current encoding rules /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is /// <see cref="TagClass.Universal"/>, but /// <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for /// the method /// </exception> public BigInteger ReadInteger(Asn1Tag expectedTag) { ReadOnlyMemory <byte> contents = GetIntegerContents(expectedTag, UniversalTagNumber.Integer, out int headerLength); // TODO: Split this for netcoreapp/netstandard to use the Big-Endian BigInteger parsing byte[] tmp = CryptoPool.Rent(contents.Length); BigInteger value; try { byte fill = (contents.Span[0] & 0x80) == 0 ? (byte)0 : (byte)0xFF; // Fill the unused portions of tmp with positive or negative padding. new Span <byte>(tmp, contents.Length, tmp.Length - contents.Length).Fill(fill); contents.CopyTo(tmp); // Convert to Little-Endian. AsnWriter.Reverse(new Span <byte>(tmp, 0, contents.Length)); value = new BigInteger(tmp); } finally { // Let CryptoPool.Return clear the whole tmp so that not even the sign bit // is returned to the array pool. CryptoPool.Return(tmp); } _data = _data.Slice(headerLength + contents.Length); return(value); }