DerBitString
using Org.BouncyCastle.Utilities;
using System;
using System.IO;
using System.Text;
namespace Org.BouncyCastle.Asn1
{
public class DerBitString : DerStringBase, Asn1BitStringParser, IAsn1Convertible
{
internal class Meta : Asn1UniversalType
{
internal static readonly Asn1UniversalType Instance = new Meta();
private Meta()
: base(typeof(DerBitString), 3)
{
}
internal override Asn1Object FromImplicitPrimitive(DerOctetString octetString)
{
return CreatePrimitive(octetString.GetOctets());
}
internal override Asn1Object FromImplicitConstructed(Asn1Sequence sequence)
{
return sequence.ToAsn1BitString();
}
}
private static readonly char[] table = new char[16] {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'
};
internal readonly byte[] contents;
public virtual int PadBits => contents[0];
public virtual int IntValue {
get {
int num = 0;
int num2 = System.Math.Min(5, contents.Length - 1);
for (int i = 1; i < num2; i++) {
num |= contents[i] << 8 * (i - 1);
}
if (1 <= num2 && num2 < 5) {
int num3 = contents[0];
byte b = (byte)(contents[num2] & (255 << num3));
num |= b << 8 * (num2 - 1);
}
return num;
}
}
public Asn1BitStringParser Parser => this;
public static DerBitString GetInstance(object obj)
{
if (obj == null)
return null;
DerBitString derBitString = obj as DerBitString;
if (derBitString != null)
return derBitString;
IAsn1Convertible asn1Convertible = obj as IAsn1Convertible;
if (asn1Convertible != null) {
DerBitString derBitString2 = asn1Convertible.ToAsn1Object() as DerBitString;
if (derBitString2 != null)
return derBitString2;
} else {
byte[] array = obj as byte[];
if (array != null)
try {
return GetInstance(Asn1Object.FromByteArray(array));
} catch (IOException ex) {
throw new ArgumentException("failed to construct BIT STRING from byte[]: " + ex.Message);
}
}
throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
}
public static DerBitString GetInstance(Asn1TaggedObject obj, bool isExplicit)
{
return (DerBitString)Meta.Instance.GetContextInstance(obj, isExplicit);
}
public DerBitString(byte data, int padBits)
{
if (padBits > 7 || padBits < 0)
throw new ArgumentException("pad bits cannot be greater than 7 or less than 0", "padBits");
contents = new byte[2] {
(byte)padBits,
data
};
}
public DerBitString(byte[] data)
: this(data, 0)
{
}
public DerBitString(byte[] data, int padBits)
{
if (data == null)
throw new ArgumentNullException("data");
if (padBits < 0 || padBits > 7)
throw new ArgumentException("must be in the range 0 to 7", "padBits");
if (data.Length == 0 && padBits != 0)
throw new ArgumentException("if 'data' is empty, 'padBits' must be 0");
contents = Arrays.Prepend(data, (byte)padBits);
}
public DerBitString(ReadOnlySpan<byte> data)
: this(data, 0)
{
}
public DerBitString(ReadOnlySpan<byte> data, int padBits)
{
if (padBits < 0 || padBits > 7)
throw new ArgumentException("must be in the range 0 to 7", "padBits");
if (data.IsEmpty && padBits != 0)
throw new ArgumentException("if 'data' is empty, 'padBits' must be 0");
contents = Arrays.Prepend(data, (byte)padBits);
}
public DerBitString(int namedBits)
{
if (namedBits == 0)
contents = new byte[1];
else {
int num = (32 - Integers.NumberOfLeadingZeros(namedBits) + 7) / 8;
byte[] array = new byte[1 + num];
for (int i = 1; i < num; i++) {
array[i] = (byte)namedBits;
namedBits >>= 8;
}
array[num] = (byte)namedBits;
int j;
for (j = 0; (namedBits & (1 << j)) == 0; j++) {
}
array[0] = (byte)j;
contents = array;
}
}
public DerBitString(Asn1Encodable obj)
: this(obj.GetDerEncoded())
{
}
internal DerBitString(byte[] contents, bool check)
{
if (check) {
if (contents == null)
throw new ArgumentNullException("contents");
if (contents.Length < 1)
throw new ArgumentException("cannot be empty", "contents");
int num = contents[0];
if (num > 0) {
if (contents.Length < 2)
throw new ArgumentException("zero length data with non-zero pad bits", "contents");
if (num > 7)
throw new ArgumentException("pad bits cannot be greater than 7 or less than 0", "contents");
}
}
this.contents = contents;
}
public virtual byte[] GetOctets()
{
if (contents[0] != 0)
throw new InvalidOperationException("attempt to get non-octet aligned data from BIT STRING");
return Arrays.CopyOfRange(contents, 1, contents.Length);
}
internal ReadOnlyMemory<byte> GetOctetsMemory()
{
if (contents[0] != 0)
throw new InvalidOperationException("attempt to get non-octet aligned data from BIT STRING");
return contents.AsMemory(1);
}
internal ReadOnlySpan<byte> GetOctetsSpan()
{
if (contents[0] != 0)
throw new InvalidOperationException("attempt to get non-octet aligned data from BIT STRING");
return contents.AsSpan(1);
}
public virtual byte[] GetBytes()
{
if (contents.Length == 1)
return Asn1OctetString.EmptyOctets;
int num = contents[0];
byte[] array = Arrays.CopyOfRange(contents, 1, contents.Length);
array[array.Length - 1] &= (byte)(255 << num);
return array;
}
internal override IAsn1Encoding GetEncoding(int encoding)
{
int num = contents[0];
if (num != 0) {
int num2 = contents.Length - 1;
byte num3 = contents[num2];
byte b = (byte)(num3 & (255 << num));
if (num3 != b)
return new PrimitiveEncodingSuffixed(0, 3, contents, b);
}
return new PrimitiveEncoding(0, 3, contents);
}
internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
{
int num = contents[0];
if (num != 0) {
int num2 = contents.Length - 1;
byte num3 = contents[num2];
byte b = (byte)(num3 & (255 << num));
if (num3 != b)
return new PrimitiveEncodingSuffixed(tagClass, tagNo, contents, b);
}
return new PrimitiveEncoding(tagClass, tagNo, contents);
}
internal sealed override DerEncoding GetEncodingDer()
{
int num = contents[0];
if (num != 0) {
int num2 = contents.Length - 1;
byte num3 = contents[num2];
byte b = (byte)(num3 & (255 << num));
if (num3 != b)
return new PrimitiveDerEncodingSuffixed(0, 3, contents, b);
}
return new PrimitiveDerEncoding(0, 3, contents);
}
internal sealed override DerEncoding GetEncodingDerImplicit(int tagClass, int tagNo)
{
int num = contents[0];
if (num != 0) {
int num2 = contents.Length - 1;
byte num3 = contents[num2];
byte b = (byte)(num3 & (255 << num));
if (num3 != b)
return new PrimitiveDerEncodingSuffixed(tagClass, tagNo, contents, b);
}
return new PrimitiveDerEncoding(tagClass, tagNo, contents);
}
protected override int Asn1GetHashCode()
{
if (contents.Length < 2)
return 1;
int num = contents[0];
int num2 = contents.Length - 1;
byte b = (byte)(contents[num2] & (255 << num));
return (Arrays.GetHashCode(contents, 0, num2) * 257) ^ b;
}
protected override bool Asn1Equals(Asn1Object asn1Object)
{
DerBitString derBitString = asn1Object as DerBitString;
if (derBitString == null)
return false;
byte[] array = contents;
byte[] array2 = derBitString.contents;
int num = array.Length;
if (array2.Length != num)
return false;
if (num == 1)
return true;
int num2 = num - 1;
for (int i = 0; i < num2; i++) {
if (array[i] != array2[i])
return false;
}
int num3 = array[0];
byte num4 = (byte)(array[num2] & (255 << num3));
byte b = (byte)(array2[num2] & (255 << num3));
return num4 == b;
}
public Stream GetBitStream()
{
return new MemoryStream(contents, 1, contents.Length - 1, false);
}
public Stream GetOctetStream()
{
int num = contents[0] & 255;
if (num != 0)
throw new IOException("expected octet-aligned bitstring, but found padBits: " + num.ToString());
return GetBitStream();
}
public override string GetString()
{
byte[] derEncoded = GetDerEncoded();
StringBuilder stringBuilder = new StringBuilder(1 + derEncoded.Length * 2);
stringBuilder.Append('#');
for (int i = 0; i != derEncoded.Length; i++) {
uint num = derEncoded[i];
stringBuilder.Append(table[num >> 4]);
stringBuilder.Append(table[num & 15]);
}
return stringBuilder.ToString();
}
internal static DerBitString CreatePrimitive(byte[] contents)
{
int num = contents.Length;
if (num < 1)
throw new ArgumentException("truncated BIT STRING detected", "contents");
int num2 = contents[0];
if (num2 > 0) {
if (num2 > 7 || num < 2)
throw new ArgumentException("invalid pad bits detected", "contents");
byte b = contents[num - 1];
if (b != (byte)(b & (255 << num2)))
return new DLBitString(contents, false);
}
return new DerBitString(contents, false);
}
}
}