001: package org.bouncycastle.bcpg;
002:
003: import java.io.*;
004:
005: /**
006: * reader for PGP objects
007: */
008: public class BCPGInputStream extends InputStream implements PacketTags {
009: InputStream in;
010: boolean next = false;
011: int nextB;
012:
013: public BCPGInputStream(InputStream in) {
014: this .in = in;
015: }
016:
017: public int available() throws IOException {
018: return in.available();
019: }
020:
021: public int read() throws IOException {
022: if (next) {
023: next = false;
024:
025: return nextB;
026: } else {
027: return in.read();
028: }
029: }
030:
031: public int read(byte[] buf, int off, int len) throws IOException {
032: if (len == 0) {
033: return 0;
034: }
035:
036: if (!next) {
037: return in.read(buf, off, len);
038: }
039:
040: // We have next byte waiting, so return it
041:
042: if (nextB < 0) {
043: return -1; // EOF
044: }
045:
046: buf[off] = (byte) nextB; // May throw NullPointerException...
047: next = false; // ...so only set this afterwards
048:
049: return 1;
050: }
051:
052: public void readFully(byte[] buf, int off, int len)
053: throws IOException {
054: //
055: // make sure we pick up nextB if set.
056: //
057: if (len > 0) {
058: int b = this .read();
059:
060: if (b < 0) {
061: throw new EOFException();
062: }
063:
064: buf[off] = (byte) b;
065: off++;
066: len--;
067: }
068:
069: while (len > 0) {
070: int l = in.read(buf, off, len);
071:
072: if (l < 0) {
073: throw new EOFException();
074: }
075:
076: off += l;
077: len -= l;
078: }
079: }
080:
081: public void readFully(byte[] buf) throws IOException {
082: readFully(buf, 0, buf.length);
083: }
084:
085: /**
086: * returns the next packet tag in the stream.
087: *
088: * @return the tag number.
089: *
090: * @throws IOException
091: */
092: public int nextPacketTag() throws IOException {
093: if (!next) {
094: try {
095: nextB = in.read();
096: } catch (EOFException e) {
097: nextB = -1;
098: }
099: }
100:
101: next = true;
102:
103: if (nextB >= 0) {
104: if ((nextB & 0x40) != 0) // new
105: {
106: return (nextB & 0x3f);
107: } else // old
108: {
109: return ((nextB & 0x3f) >> 2);
110: }
111: }
112:
113: return nextB;
114: }
115:
116: public Packet readPacket() throws IOException {
117: int hdr = this .read();
118:
119: if (hdr < 0) {
120: return null;
121: }
122:
123: if ((hdr & 0x80) == 0) {
124: throw new IOException("invalid header encountered");
125: }
126:
127: boolean newPacket = (hdr & 0x40) != 0;
128: int tag = 0;
129: int bodyLen = 0;
130: boolean partial = false;
131:
132: if (newPacket) {
133: tag = hdr & 0x3f;
134:
135: int l = this .read();
136:
137: if (l < 192) {
138: bodyLen = l;
139: } else if (l <= 223) {
140: int b = in.read();
141:
142: bodyLen = ((l - 192) << 8) + (b) + 192;
143: } else if (l == 255) {
144: bodyLen = (in.read() << 24) | (in.read() << 16)
145: | (in.read() << 8) | in.read();
146: } else {
147: partial = true;
148: bodyLen = 1 << (l & 0x1f);
149: }
150: } else {
151: int lengthType = hdr & 0x3;
152:
153: tag = (hdr & 0x3f) >> 2;
154:
155: switch (lengthType) {
156: case 0:
157: bodyLen = this .read();
158: break;
159: case 1:
160: bodyLen = (this .read() << 8) | this .read();
161: break;
162: case 2:
163: bodyLen = (this .read() << 24) | (this .read() << 16)
164: | (this .read() << 8) | this .read();
165: break;
166: case 3:
167: partial = true;
168: break;
169: default:
170: throw new IOException("unknown length type encountered");
171: }
172: }
173:
174: BCPGInputStream objStream;
175:
176: if (bodyLen == 0 && partial) {
177: objStream = this ;
178: } else {
179: objStream = new BCPGInputStream(new PartialInputStream(
180: this , partial, bodyLen));
181: }
182:
183: switch (tag) {
184: case RESERVED:
185: return new InputStreamPacket(objStream);
186: case PUBLIC_KEY_ENC_SESSION:
187: return new PublicKeyEncSessionPacket(objStream);
188: case SIGNATURE:
189: return new SignaturePacket(objStream);
190: case SYMMETRIC_KEY_ENC_SESSION:
191: return new SymmetricKeyEncSessionPacket(objStream);
192: case ONE_PASS_SIGNATURE:
193: return new OnePassSignaturePacket(objStream);
194: case SECRET_KEY:
195: return new SecretKeyPacket(objStream);
196: case PUBLIC_KEY:
197: return new PublicKeyPacket(objStream);
198: case SECRET_SUBKEY:
199: return new SecretSubkeyPacket(objStream);
200: case COMPRESSED_DATA:
201: return new CompressedDataPacket(objStream);
202: case SYMMETRIC_KEY_ENC:
203: return new SymmetricEncDataPacket(objStream);
204: case MARKER:
205: return new MarkerPacket(objStream);
206: case LITERAL_DATA:
207: return new LiteralDataPacket(objStream);
208: case TRUST:
209: return new TrustPacket(objStream);
210: case USER_ID:
211: return new UserIDPacket(objStream);
212: case USER_ATTRIBUTE:
213: return new UserAttributePacket(objStream);
214: case PUBLIC_SUBKEY:
215: return new PublicSubkeyPacket(objStream);
216: case SYM_ENC_INTEGRITY_PRO:
217: return new SymmetricEncIntegrityPacket(objStream);
218: case MOD_DETECTION_CODE:
219: return new ModDetectionCodePacket(objStream);
220: case EXPERIMENTAL_1:
221: case EXPERIMENTAL_2:
222: case EXPERIMENTAL_3:
223: case EXPERIMENTAL_4:
224: return new ExperimentalPacket(tag, objStream);
225: default:
226: throw new IOException("unknown packet type encountered: "
227: + tag);
228: }
229: }
230:
231: public void close() throws IOException {
232: in.close();
233: }
234:
235: /**
236: * a stream that overlays our input stream, allowing the user to only read a segment of it.
237: */
238: private static class PartialInputStream extends InputStream {
239: private BCPGInputStream in;
240: private boolean partial;
241: private int dataLength;
242:
243: PartialInputStream(BCPGInputStream in, boolean partial,
244: int dataLength) {
245: this .in = in;
246: this .partial = partial;
247: this .dataLength = dataLength;
248: }
249:
250: public int available() throws IOException {
251: int avail = in.available();
252:
253: if (avail <= dataLength) {
254: return avail;
255: } else {
256: if (partial && dataLength == 0) {
257: return 1;
258: }
259: return dataLength;
260: }
261: }
262:
263: private int loadDataLength() throws IOException {
264: int l = in.read();
265:
266: if (l < 0) {
267: return -1;
268: }
269:
270: partial = false;
271: if (l < 192) {
272: dataLength = l;
273: } else if (l <= 223) {
274: dataLength = ((l - 192) << 8) + (in.read()) + 192;
275: } else if (l == 255) {
276: dataLength = (in.read() << 24) | (in.read() << 16)
277: | (in.read() << 8) | in.read();
278: } else {
279: partial = true;
280: dataLength = 1 << (l & 0x1f);
281: }
282:
283: return dataLength;
284: }
285:
286: public int read(byte[] buf, int offset, int len)
287: throws IOException {
288: if (dataLength > 0) {
289: int readLen = (dataLength > len) ? len : dataLength;
290:
291: readLen = in.read(buf, offset, readLen);
292:
293: dataLength -= readLen;
294:
295: return readLen;
296: } else if (partial) {
297: if (loadDataLength() < 0) {
298: return -1;
299: }
300:
301: return this .read(buf, offset, len);
302: }
303:
304: return -1;
305: }
306:
307: public int read() throws IOException {
308: if (dataLength > 0) {
309: dataLength--;
310: return in.read();
311: } else if (partial) {
312: if (loadDataLength() < 0) {
313: return -1;
314: }
315:
316: return this .read();
317: }
318:
319: return -1;
320: }
321: }
322: }
|