Exemplo n.º 1
0
        /// <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);
        }