Files
hcs/Hcs.ClientNet/GostCryptography/Asn1/Ber/Asn1BerDecodeBuffer.cs

401 lines
11 KiB
C#

using GostCryptography.Properties;
using System;
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1BerDecodeBuffer : Asn1DecodeBuffer
{
private readonly IntHolder _lenHolder;
private readonly Asn1Tag _tagHolder;
private Asn1Tag _lastParsedTag;
private MemoryStream _openTypeCaptureBuffer;
private MemoryStream _parserCaptureBuffer;
public Asn1BerDecodeBuffer(byte[] msgdata)
: base(msgdata)
{
_tagHolder = new Asn1Tag();
_lenHolder = new IntHolder();
}
public Asn1BerDecodeBuffer(Stream inputStream)
: base(inputStream)
{
_tagHolder = new Asn1Tag();
_lenHolder = new IntHolder();
}
public virtual Asn1Tag LastTag
{
get { return _lastParsedTag; }
}
public static int CalcIndefLen(byte[] data, int offset, int len)
{
Asn1BerDecodeBuffer buffer;
if ((offset == 0) && (len == data.Length))
{
buffer = new Asn1BerDecodeBuffer(data);
}
else
{
var destinationArray = new byte[len];
Array.Copy(data, offset, destinationArray, 0, len);
buffer = new Asn1BerDecodeBuffer(destinationArray);
}
var tag = new Asn1Tag();
var num = buffer.DecodeTagAndLength(tag);
if (num == Asn1Status.IndefiniteLength)
{
var num2 = 1;
num = 0;
while (num2 > 0)
{
var byteCount = buffer.ByteCount;
var num4 = buffer.DecodeTagAndLength(tag);
num += buffer.ByteCount - byteCount;
if (num4 > 0)
{
buffer.Skip(num4);
num += num4;
}
else
{
if (num4 == Asn1Status.IndefiniteLength)
{
num2++;
continue;
}
if (tag.IsEoc() && (num4 == 0))
{
num2--;
}
}
}
}
return num;
}
public virtual int DecodeLength()
{
var num3 = 0;
var num2 = Read();
if (num2 < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
if (num2 <= 0x80)
{
if (num2 == 0x80)
{
return Asn1Status.IndefiniteLength;
}
return num2;
}
var num = num2 & 0x7f;
if (num > 4)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
while (num > 0)
{
num2 = Read();
if (num2 < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
num3 = (num3 * 0x100) + num2;
num--;
}
return num3;
}
public virtual byte[] DecodeOpenType()
{
return DecodeOpenType(true);
}
public virtual byte[] DecodeOpenType(bool saveData)
{
if (saveData)
{
if (_openTypeCaptureBuffer == null)
{
_openTypeCaptureBuffer = new MemoryStream(0x100);
}
else
{
_openTypeCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_openTypeCaptureBuffer.SetLength(0L);
}
AddCaptureBuffer(_openTypeCaptureBuffer);
}
DecodeOpenTypeElement(_tagHolder, _lenHolder, saveData);
if (saveData)
{
var buffer = _openTypeCaptureBuffer.ToArray();
RemoveCaptureBuffer(_openTypeCaptureBuffer);
return buffer;
}
return null;
}
private void DecodeOpenTypeElement(Asn1Tag tag, IntHolder len, bool saveData)
{
var nbytes = DecodeTagAndLength(tag);
var byteCount = base.ByteCount;
if (nbytes > 0)
{
if (saveData)
{
Capture(nbytes);
}
else
{
Skip(nbytes);
}
}
else if (nbytes == Asn1Status.IndefiniteLength)
{
MovePastEoc(saveData);
}
len.Value = base.ByteCount - byteCount;
}
public virtual void DecodeTag(Asn1Tag tag)
{
var num = Read();
if (num < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
tag.Class = (short)(num & 0xc0);
tag.Form = (short)(num & 0x20);
tag.IdCode = num & 0x1f;
if (tag.IdCode == 0x1f)
{
var num2 = 0L;
var num3 = 0;
do
{
num = Read();
if (num < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
num2 = (num2 * 0x80L) + (num & 0x7f);
if ((num2 > 0x7fffffffL) || (num3++ > 8))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidTagValue);
}
}
while ((num & 0x80) != 0);
tag.IdCode = (int)num2;
}
_lastParsedTag = tag;
}
public virtual int DecodeTagAndLength(Asn1Tag tag)
{
DecodeTag(tag);
return DecodeLength();
}
public virtual bool MatchTag(Asn1Tag tag)
{
return MatchTag(tag.Class, tag.Form, tag.IdCode, null, null);
}
public virtual bool MatchTag(Asn1Tag tag, Asn1Tag parsedTag, IntHolder parsedLen)
{
return MatchTag(tag.Class, tag.Form, tag.IdCode, parsedTag, parsedLen);
}
public virtual bool MatchTag(short tagClass, short tagForm, int tagIdCode, Asn1Tag parsedTag, IntHolder parsedLen)
{
Mark();
var tag = parsedTag ?? _tagHolder;
var holder = parsedLen ?? _lenHolder;
holder.Value = DecodeTagAndLength(tag);
if (!tag.Equals(tagClass, tagForm, tagIdCode))
{
Reset();
return false;
}
return true;
}
protected void MovePastEoc(bool saveData)
{
var tag = new Asn1Tag();
var num = 1;
while (num > 0)
{
var nbytes = DecodeTagAndLength(tag);
if (nbytes > 0)
{
if (saveData)
{
Capture(nbytes);
}
else
{
Skip(nbytes);
}
}
else if (nbytes == Asn1Status.IndefiniteLength)
{
num++;
}
else if (tag.IsEoc() && (nbytes == 0))
{
num--;
}
}
}
public virtual void Parse(IAsn1TaggedEventHandler handler)
{
if (_parserCaptureBuffer == null)
{
RemoveCaptureBuffer(_parserCaptureBuffer);
}
if (_parserCaptureBuffer == null)
{
_parserCaptureBuffer = new MemoryStream(0x100);
AddCaptureBuffer(_parserCaptureBuffer);
}
else
{
_parserCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_parserCaptureBuffer.SetLength(0L);
}
ParseElement(handler, _tagHolder, _lenHolder);
}
private void ParseCons(IAsn1TaggedEventHandler handler, int len)
{
var tag2 = new Asn1Tag();
var holder = new IntHolder();
var byteCount = base.ByteCount;
while (true)
{
ParseElement(handler, tag2, holder);
if (len == Asn1Status.IndefiniteLength)
{
if (tag2.IsEoc() && (holder.Value == 0))
{
return;
}
continue;
}
if ((base.ByteCount - byteCount) >= len)
{
return;
}
}
}
private void ParseElement(IAsn1TaggedEventHandler handler, Asn1Tag tag, IntHolder len)
{
_parserCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_parserCaptureBuffer.SetLength(0L);
len.Value = DecodeTagAndLength(tag);
if (!tag.IsEoc() || (len.Value != 0))
{
handler.StartElement(tag, len.Value, _parserCaptureBuffer.ToArray());
_parserCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_parserCaptureBuffer.SetLength(0L);
if ((len.Value > 0) || (len.Value == Asn1Status.IndefiniteLength))
{
if (tag.Constructed)
{
ParseCons(handler, len.Value);
}
else
{
ParsePrim(handler, len.Value);
}
}
handler.EndElement(tag);
}
}
private void ParsePrim(IAsn1TaggedEventHandler handler, int len)
{
var buffer = new byte[len];
Read(buffer);
handler.Contents(buffer);
}
public virtual Asn1Tag PeekTag()
{
var parsedTag = new Asn1Tag();
PeekTag(parsedTag);
return parsedTag;
}
public virtual void PeekTag(Asn1Tag parsedTag)
{
Mark();
DecodeTag(parsedTag);
Reset();
}
public override int ReadByte()
{
return Read();
}
}
}