#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) #pragma warning disable using System; using System.IO; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO; namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Bcpg { /// Reader for PGP objects. public class BcpgInputStream : BaseInputStream { private Stream m_in; private bool next = false; private int nextB; internal static BcpgInputStream Wrap( Stream inStr) { if (inStr is BcpgInputStream) { return (BcpgInputStream) inStr; } return new BcpgInputStream(inStr); } private BcpgInputStream( Stream inputStream) { this.m_in = inputStream; } public override int ReadByte() { if (next) { next = false; return nextB; } return m_in.ReadByte(); } public override int Read( byte[] buffer, int offset, int count) { // Strangely, when count == 0, we should still attempt to read a byte // if (count == 0) // return 0; if (!next) return m_in.Read(buffer, offset, count); // We have next byte waiting, so return it if (nextB < 0) return 0; // EndOfStream if (buffer == null) throw new ArgumentNullException("buffer"); buffer[offset] = (byte) nextB; next = false; return 1; } public byte[] ReadAll() { return Streams.ReadAll(this); } public void ReadFully( byte[] buffer, int off, int len) { if (Streams.ReadFully(this, buffer, off, len) < len) throw new EndOfStreamException(); } public void ReadFully( byte[] buffer) { ReadFully(buffer, 0, buffer.Length); } /// Returns the next packet tag in the stream. public PacketTag NextPacketTag() { if (!next) { try { nextB = m_in.ReadByte(); } catch (EndOfStreamException) { nextB = -1; } next = true; } if (nextB < 0) return (PacketTag)nextB; int maskB = nextB & 0x3f; if ((nextB & 0x40) == 0) // old { maskB >>= 2; } return (PacketTag)maskB; } public Packet ReadPacket() { int hdr = this.ReadByte(); if (hdr < 0) { return null; } if ((hdr & 0x80) == 0) { throw new IOException("invalid header encountered"); } bool newPacket = (hdr & 0x40) != 0; PacketTag tag = 0; int bodyLen = 0; bool partial = false; if (newPacket) { tag = (PacketTag)(hdr & 0x3f); int l = this.ReadByte(); if (l < 192) { bodyLen = l; } else if (l <= 223) { int b = m_in.ReadByte(); bodyLen = ((l - 192) << 8) + (b) + 192; } else if (l == 255) { bodyLen = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16) | (m_in.ReadByte() << 8) | m_in.ReadByte(); } else { partial = true; bodyLen = 1 << (l & 0x1f); } } else { int lengthType = hdr & 0x3; tag = (PacketTag)((hdr & 0x3f) >> 2); switch (lengthType) { case 0: bodyLen = this.ReadByte(); break; case 1: bodyLen = (this.ReadByte() << 8) | this.ReadByte(); break; case 2: bodyLen = (this.ReadByte() << 24) | (this.ReadByte() << 16) | (this.ReadByte() << 8) | this.ReadByte(); break; case 3: partial = true; break; default: throw new IOException("unknown length type encountered"); } } BcpgInputStream objStream; if (bodyLen == 0 && partial) { objStream = this; } else { PartialInputStream pis = new PartialInputStream(this, partial, bodyLen); #if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE || NETFX_CORE Stream buf = pis; #else Stream buf = new BufferedStream(pis); #endif objStream = new BcpgInputStream(buf); } switch (tag) { case PacketTag.Reserved: return new InputStreamPacket(objStream); case PacketTag.PublicKeyEncryptedSession: return new PublicKeyEncSessionPacket(objStream); case PacketTag.Signature: return new SignaturePacket(objStream); case PacketTag.SymmetricKeyEncryptedSessionKey: return new SymmetricKeyEncSessionPacket(objStream); case PacketTag.OnePassSignature: return new OnePassSignaturePacket(objStream); case PacketTag.SecretKey: return new SecretKeyPacket(objStream); case PacketTag.PublicKey: return new PublicKeyPacket(objStream); case PacketTag.SecretSubkey: return new SecretSubkeyPacket(objStream); case PacketTag.CompressedData: return new CompressedDataPacket(objStream); case PacketTag.SymmetricKeyEncrypted: return new SymmetricEncDataPacket(objStream); case PacketTag.Marker: return new MarkerPacket(objStream); case PacketTag.LiteralData: return new LiteralDataPacket(objStream); case PacketTag.Trust: return new TrustPacket(objStream); case PacketTag.UserId: return new UserIdPacket(objStream); case PacketTag.UserAttribute: return new UserAttributePacket(objStream); case PacketTag.PublicSubkey: return new PublicSubkeyPacket(objStream); case PacketTag.SymmetricEncryptedIntegrityProtected: return new SymmetricEncIntegrityPacket(objStream); case PacketTag.ModificationDetectionCode: return new ModDetectionCodePacket(objStream); case PacketTag.Experimental1: case PacketTag.Experimental2: case PacketTag.Experimental3: case PacketTag.Experimental4: return new ExperimentalPacket(tag, objStream); default: throw new IOException("unknown packet type encountered: " + tag); } } public PacketTag SkipMarkerPackets() { PacketTag tag; while ((tag = NextPacketTag()) == PacketTag.Marker) { ReadPacket(); } return tag; } #if PORTABLE || NETFX_CORE protected override void Dispose(bool disposing) { if (disposing) { BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(m_in); } base.Dispose(disposing); } #else public override void Close() { BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(m_in); base.Close(); } #endif /// /// A stream that overlays our input stream, allowing the user to only read a segment of it. /// NB: dataLength will be negative if the segment length is in the upper range above 2**31. /// private class PartialInputStream : BaseInputStream { private BcpgInputStream m_in; private bool partial; private int dataLength; internal PartialInputStream( BcpgInputStream bcpgIn, bool partial, int dataLength) { this.m_in = bcpgIn; this.partial = partial; this.dataLength = dataLength; } public override int ReadByte() { do { if (dataLength != 0) { int ch = m_in.ReadByte(); if (ch < 0) { throw new EndOfStreamException("Premature end of stream in PartialInputStream"); } dataLength--; return ch; } } while (partial && ReadPartialDataLength() >= 0); return -1; } public override int Read(byte[] buffer, int offset, int count) { do { if (dataLength != 0) { int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; int len = m_in.Read(buffer, offset, readLen); if (len < 1) { throw new EndOfStreamException("Premature end of stream in PartialInputStream"); } dataLength -= len; return len; } } while (partial && ReadPartialDataLength() >= 0); return 0; } private int ReadPartialDataLength() { int l = m_in.ReadByte(); if (l < 0) { return -1; } partial = false; if (l < 192) { dataLength = l; } else if (l <= 223) { dataLength = ((l - 192) << 8) + (m_in.ReadByte()) + 192; } else if (l == 255) { dataLength = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16) | (m_in.ReadByte() << 8) | m_in.ReadByte(); } else { partial = true; dataLength = 1 << (l & 0x1f); } return 0; } } } } #pragma warning restore #endif