455 lines
11 KiB
C#
455 lines
11 KiB
C#
using GostCryptography.Properties;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Text;
|
|
|
|
namespace GostCryptography.Asn1.Ber
|
|
{
|
|
[Serializable]
|
|
public class Asn1BitString : Asn1Type
|
|
{
|
|
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, BitStringTypeCode);
|
|
|
|
[NonSerialized]
|
|
public byte[] Value;
|
|
|
|
[NonSerialized]
|
|
public int NumBits;
|
|
|
|
public Asn1BitString()
|
|
{
|
|
NumBits = 0;
|
|
Value = null;
|
|
}
|
|
|
|
public Asn1BitString(bool[] bitValues)
|
|
{
|
|
AllocBitArray(bitValues.Length);
|
|
|
|
var index = 0;
|
|
var num4 = 0x80;
|
|
var num = 0;
|
|
var num2 = 0;
|
|
|
|
while (num < bitValues.Length)
|
|
{
|
|
if (bitValues[num])
|
|
{
|
|
num2 |= num4;
|
|
}
|
|
|
|
num4 = num4 >> 1;
|
|
|
|
if (num4 == 0)
|
|
{
|
|
Value[index++] = (byte)num2;
|
|
num4 = 0x80;
|
|
num2 = 0;
|
|
}
|
|
|
|
num++;
|
|
}
|
|
|
|
if (num4 != 0x80)
|
|
{
|
|
Value[index] = (byte)num2;
|
|
}
|
|
}
|
|
|
|
public Asn1BitString(BitArray bitArray)
|
|
{
|
|
AllocBitArray(bitArray.Length);
|
|
|
|
var index = 0;
|
|
var num4 = 0x80;
|
|
var num = 0;
|
|
var num2 = 0;
|
|
|
|
while (num < bitArray.Length)
|
|
{
|
|
if (bitArray.Get(num))
|
|
{
|
|
num2 |= num4;
|
|
}
|
|
|
|
num4 = num4 >> 1;
|
|
|
|
if (num4 == 0)
|
|
{
|
|
Value[index++] = (byte)num2;
|
|
num4 = 0x80;
|
|
num2 = 0;
|
|
}
|
|
|
|
num++;
|
|
}
|
|
|
|
if (num4 != 0x80)
|
|
{
|
|
Value[index] = (byte)num2;
|
|
}
|
|
}
|
|
|
|
public Asn1BitString(string value)
|
|
{
|
|
var numbits = new IntHolder();
|
|
Value = Asn1Value.ParseString(value, numbits);
|
|
|
|
NumBits = numbits.Value;
|
|
}
|
|
|
|
public Asn1BitString(int numBits, byte[] data)
|
|
{
|
|
NumBits = numBits;
|
|
Value = data;
|
|
}
|
|
|
|
private void AllocBitArray(int numbits)
|
|
{
|
|
NumBits = numbits;
|
|
|
|
var num = (NumBits + 7) / 8;
|
|
|
|
if ((Value == null) || (Value.Length < num))
|
|
{
|
|
Value = new byte[num];
|
|
}
|
|
}
|
|
|
|
public virtual void Clear(int bitIndex)
|
|
{
|
|
this[bitIndex] = false;
|
|
}
|
|
|
|
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
|
|
{
|
|
var elemLength = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
|
|
var lastTag = buffer.LastTag;
|
|
|
|
if ((lastTag == null) || !lastTag.Constructed)
|
|
{
|
|
if (elemLength < 0)
|
|
{
|
|
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
|
|
}
|
|
|
|
if (elemLength != 0)
|
|
{
|
|
var num8 = elemLength - 1;
|
|
var num7 = buffer.Read();
|
|
|
|
if (num7 < 0)
|
|
{
|
|
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
|
|
}
|
|
|
|
if ((num7 < 0) || (num7 > 7))
|
|
{
|
|
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfBitString, num7);
|
|
}
|
|
|
|
if ((num8 == 0) && (num7 != 0))
|
|
{
|
|
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
|
|
}
|
|
|
|
NumBits = (num8 * 8) - num7;
|
|
Value = new byte[num8];
|
|
buffer.Read(Value);
|
|
}
|
|
else
|
|
{
|
|
NumBits = 0;
|
|
Value = null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var num3 = 0;
|
|
var offset = 0;
|
|
var index = -1;
|
|
var num6 = 0;
|
|
|
|
var context = new Asn1BerDecodeContext(buffer, elemLength);
|
|
|
|
while (!context.Expired())
|
|
{
|
|
var nbytes = MatchTag(buffer, Tag);
|
|
|
|
if (nbytes <= 0)
|
|
{
|
|
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
|
|
}
|
|
|
|
num3 += nbytes;
|
|
|
|
if (offset == 0)
|
|
{
|
|
AllocBitArray(num3 * 8);
|
|
}
|
|
else
|
|
{
|
|
ReallocBitArray(num3 * 8);
|
|
}
|
|
|
|
index = offset;
|
|
buffer.Read(Value, offset, nbytes);
|
|
offset = num3;
|
|
}
|
|
|
|
if (index >= 0)
|
|
{
|
|
num6 = Value[index];
|
|
|
|
if (((offset - index) - 1) > 0)
|
|
{
|
|
Array.Copy(Value, index + 1, Value, index, (offset - index) - 1);
|
|
}
|
|
|
|
num3--;
|
|
}
|
|
|
|
if ((num6 < 0) || (num6 > 7))
|
|
{
|
|
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfBitString, num6);
|
|
}
|
|
|
|
ReallocBitArray((num3 * 8) - num6);
|
|
|
|
if (elemLength == Asn1Status.IndefiniteLength)
|
|
{
|
|
MatchTag(buffer, Asn1Tag.Eoc);
|
|
}
|
|
}
|
|
|
|
buffer.TypeCode = 3;
|
|
}
|
|
|
|
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
|
|
{
|
|
var length = (NumBits + 7) / 8;
|
|
var num2 = NumBits % 8;
|
|
|
|
if (num2 != 0)
|
|
{
|
|
num2 = 8 - num2;
|
|
Value[length - 1] = (byte)(Value[length - 1] & ((byte)~((1 << num2) - 1)));
|
|
}
|
|
|
|
if (length != 0)
|
|
{
|
|
buffer.Copy(Value, 0, length);
|
|
}
|
|
|
|
buffer.Copy((byte)num2);
|
|
length++;
|
|
|
|
if (explicitTagging)
|
|
{
|
|
length += buffer.EncodeTagAndLength(Tag, length);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
|
|
{
|
|
outs.EncodeBitString(Value, NumBits, explicitTagging, Tag);
|
|
}
|
|
|
|
public override bool Equals(object value)
|
|
{
|
|
var str = value as Asn1BitString;
|
|
|
|
if (str == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Equals(str.NumBits, str.Value);
|
|
}
|
|
|
|
public virtual bool Equals(int nbits, byte[] value)
|
|
{
|
|
if (nbits != NumBits)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var num = ((nbits - 1) / 8) + 1;
|
|
|
|
for (var i = 0; i < num; ++i)
|
|
{
|
|
if (value[i] != Value[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public virtual bool Get(int bitno)
|
|
{
|
|
var index = bitno / 8;
|
|
var num2 = 1 << (7 - (bitno % 8));
|
|
|
|
if ((Value != null) && (Value.Length >= index))
|
|
{
|
|
int num3 = Value[index];
|
|
return ((num3 & num2) != 0);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return (Value != null) ? Value.GetHashCode() : base.GetHashCode();
|
|
}
|
|
|
|
private void ReallocBitArray(int numbits)
|
|
{
|
|
NumBits = numbits;
|
|
var num = (NumBits + 7) / 8;
|
|
|
|
if (Value.Length != num)
|
|
{
|
|
var value = Value;
|
|
Value = new byte[num];
|
|
|
|
if (value != null)
|
|
{
|
|
Array.Copy(value, 0, Value, 0, Math.Min(value.Length, num));
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void Set(int bitIndex)
|
|
{
|
|
Set(bitIndex, true);
|
|
}
|
|
|
|
public virtual void Set(int bitIndex, bool value)
|
|
{
|
|
var index = bitIndex / 8;
|
|
var num2 = 1 << (7 - (bitIndex % 8));
|
|
var num3 = index + 1;
|
|
|
|
if (Value == null)
|
|
{
|
|
Value = new byte[num3];
|
|
}
|
|
else if (Value.Length < num3)
|
|
{
|
|
var destinationArray = new byte[num3];
|
|
Array.Copy(Value, 0, destinationArray, 0, Value.Length);
|
|
Value = destinationArray;
|
|
}
|
|
|
|
int num4 = Value[index];
|
|
num4 = value ? (num4 | num2) : (num4 & ~num2);
|
|
Value[index] = (byte)num4;
|
|
|
|
if ((bitIndex + 1) > NumBits)
|
|
{
|
|
NumBits = bitIndex + 1;
|
|
}
|
|
}
|
|
|
|
public virtual bool[] ToBoolArray()
|
|
{
|
|
var flagArray = new bool[NumBits];
|
|
|
|
var num4 = 0;
|
|
var numbits = NumBits;
|
|
|
|
foreach (var num3 in Value)
|
|
{
|
|
var num5 = 0x80;
|
|
var num = (numbits < 8) ? numbits : 8;
|
|
|
|
for (var j = 0; j < num; ++j)
|
|
{
|
|
flagArray[num4++] = (num3 & num5) != 0;
|
|
num5 = num5 >> 1;
|
|
}
|
|
|
|
numbits -= 8;
|
|
}
|
|
|
|
return flagArray;
|
|
}
|
|
|
|
public virtual string ToHexString()
|
|
{
|
|
var str = new StringBuilder("").ToString();
|
|
|
|
foreach (var b in Value)
|
|
{
|
|
str = str + Asn1Util.ToHexString(b);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
var str = new StringBuilder("").ToString();
|
|
|
|
if (NumBits <= 0x10)
|
|
{
|
|
if (NumBits != 0)
|
|
{
|
|
var flagArray = ToBoolArray();
|
|
|
|
foreach (bool b in flagArray)
|
|
{
|
|
str = str + (b ? "1" : "0");
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
var num2 = 4;
|
|
var capacity = (NumBits + 3) / 4;
|
|
var builder = new StringBuilder(capacity);
|
|
|
|
if (Value != null)
|
|
{
|
|
var num4 = 0;
|
|
var index = 0;
|
|
|
|
while (num4 < capacity)
|
|
{
|
|
var num6 = (Value[index] >> num2) & 15;
|
|
builder.Append((char)(num6 + ((num6 >= 10) ? 0x57 : 0x30)));
|
|
num2 -= 4;
|
|
|
|
if (num2 < 0)
|
|
{
|
|
num2 = 4;
|
|
index++;
|
|
}
|
|
|
|
num4++;
|
|
}
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
public virtual bool this[int bitIndex]
|
|
{
|
|
get { return Get(bitIndex); }
|
|
set { Set(bitIndex, value); }
|
|
}
|
|
|
|
public override int Length
|
|
{
|
|
get { return NumBits; }
|
|
}
|
|
}
|
|
}
|