218 lines
4.5 KiB
C#
218 lines
4.5 KiB
C#
using System;
|
|
using System.Text;
|
|
using Org.BouncyCastle.Math;
|
|
using Org.BouncyCastle.Utilities;
|
|
|
|
namespace Org.BouncyCastle.Asn1;
|
|
|
|
public class DerBitString : DerStringBase
|
|
{
|
|
private static readonly char[] table = new char[16]
|
|
{
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
'A', 'B', 'C', 'D', 'E', 'F'
|
|
};
|
|
|
|
protected readonly byte[] mData;
|
|
|
|
protected readonly int mPadBits;
|
|
|
|
public virtual int PadBits => mPadBits;
|
|
|
|
public virtual int IntValue
|
|
{
|
|
get
|
|
{
|
|
int num = 0;
|
|
int num2 = System.Math.Min(4, mData.Length);
|
|
for (int i = 0; i < num2; i++)
|
|
{
|
|
num |= mData[i] << 8 * i;
|
|
}
|
|
if (mPadBits > 0 && num2 == mData.Length)
|
|
{
|
|
int num3 = (1 << mPadBits) - 1;
|
|
num &= ~(num3 << 8 * (num2 - 1));
|
|
}
|
|
return num;
|
|
}
|
|
}
|
|
|
|
public static DerBitString GetInstance(object obj)
|
|
{
|
|
if (obj == null || obj is DerBitString)
|
|
{
|
|
return (DerBitString)obj;
|
|
}
|
|
if (obj is byte[])
|
|
{
|
|
try
|
|
{
|
|
return (DerBitString)Asn1Object.FromByteArray((byte[])obj);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new ArgumentException("encoding error in GetInstance: " + ex.ToString());
|
|
}
|
|
}
|
|
throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
|
|
}
|
|
|
|
public static DerBitString GetInstance(Asn1TaggedObject obj, bool isExplicit)
|
|
{
|
|
Asn1Object asn1Object = obj.GetObject();
|
|
if (isExplicit || asn1Object is DerBitString)
|
|
{
|
|
return GetInstance(asn1Object);
|
|
}
|
|
return FromAsn1Octets(((Asn1OctetString)asn1Object).GetOctets());
|
|
}
|
|
|
|
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");
|
|
}
|
|
mData = Arrays.Clone(data);
|
|
mPadBits = padBits;
|
|
}
|
|
|
|
public DerBitString(byte[] data)
|
|
: this(data, 0)
|
|
{
|
|
}
|
|
|
|
public DerBitString(int namedBits)
|
|
{
|
|
if (namedBits == 0)
|
|
{
|
|
mData = new byte[0];
|
|
mPadBits = 0;
|
|
return;
|
|
}
|
|
int num = BigInteger.BitLen(namedBits);
|
|
int num2 = (num + 7) / 8;
|
|
byte[] array = new byte[num2];
|
|
num2--;
|
|
for (int i = 0; i < num2; i++)
|
|
{
|
|
array[i] = (byte)namedBits;
|
|
namedBits >>= 8;
|
|
}
|
|
array[num2] = (byte)namedBits;
|
|
int j;
|
|
for (j = 0; (namedBits & (1 << j)) == 0; j++)
|
|
{
|
|
}
|
|
mData = array;
|
|
mPadBits = j;
|
|
}
|
|
|
|
public DerBitString(Asn1Encodable obj)
|
|
: this(obj.GetDerEncoded())
|
|
{
|
|
}
|
|
|
|
public virtual byte[] GetOctets()
|
|
{
|
|
if (mPadBits != 0)
|
|
{
|
|
throw new InvalidOperationException("attempt to get non-octet aligned data from BIT STRING");
|
|
}
|
|
return Arrays.Clone(mData);
|
|
}
|
|
|
|
public virtual byte[] GetBytes()
|
|
{
|
|
byte[] array = Arrays.Clone(mData);
|
|
if (mPadBits > 0)
|
|
{
|
|
byte[] array3;
|
|
byte[] array2 = (array3 = array);
|
|
int num = array.Length - 1;
|
|
nint num2 = num;
|
|
array2[num] = (byte)(array3[num2] & (byte)(255 << mPadBits));
|
|
}
|
|
return array;
|
|
}
|
|
|
|
internal override void Encode(DerOutputStream derOut)
|
|
{
|
|
if (mPadBits > 0)
|
|
{
|
|
int num = mData[mData.Length - 1];
|
|
int num2 = (1 << mPadBits) - 1;
|
|
int num3 = num & num2;
|
|
if (num3 != 0)
|
|
{
|
|
byte[] array = Arrays.Prepend(mData, (byte)mPadBits);
|
|
array[^1] = (byte)(num ^ num3);
|
|
derOut.WriteEncoded(3, array);
|
|
return;
|
|
}
|
|
}
|
|
derOut.WriteEncoded(3, (byte)mPadBits, mData);
|
|
}
|
|
|
|
protected override int Asn1GetHashCode()
|
|
{
|
|
int num = mPadBits;
|
|
return num.GetHashCode() ^ Arrays.GetHashCode(mData);
|
|
}
|
|
|
|
protected override bool Asn1Equals(Asn1Object asn1Object)
|
|
{
|
|
if (!(asn1Object is DerBitString derBitString))
|
|
{
|
|
return false;
|
|
}
|
|
if (mPadBits == derBitString.mPadBits)
|
|
{
|
|
return Arrays.AreEqual(mData, derBitString.mData);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override string GetString()
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder("#");
|
|
byte[] derEncoded = GetDerEncoded();
|
|
for (int i = 0; i != derEncoded.Length; i++)
|
|
{
|
|
uint num = derEncoded[i];
|
|
stringBuilder.Append(table[(num >> 4) & 0xF]);
|
|
stringBuilder.Append(table[derEncoded[i] & 0xF]);
|
|
}
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
internal static DerBitString FromAsn1Octets(byte[] octets)
|
|
{
|
|
if (octets.Length < 1)
|
|
{
|
|
throw new ArgumentException("truncated BIT STRING detected", "octets");
|
|
}
|
|
int num = octets[0];
|
|
byte[] array = Arrays.CopyOfRange(octets, 1, octets.Length);
|
|
if (num > 0 && num < 8 && array.Length > 0)
|
|
{
|
|
int num2 = array[^1];
|
|
int num3 = (1 << num) - 1;
|
|
if ((num2 & num3) != 0)
|
|
{
|
|
return new BerBitString(array, num);
|
|
}
|
|
}
|
|
return new DerBitString(array, num);
|
|
}
|
|
}
|