001: package org.bouncycastle.openpgp;
002:
003: import java.io.IOException;
004: import java.io.InputStream;
005: import java.security.DigestInputStream;
006: import java.security.MessageDigest;
007:
008: import org.bouncycastle.bcpg.InputStreamPacket;
009: import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
010: import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
011:
012: public abstract class PGPEncryptedData implements
013: SymmetricKeyAlgorithmTags {
014: protected class TruncatedStream extends InputStream {
015: int[] lookAhead = new int[22];
016: int bufPtr;
017: InputStream in;
018:
019: TruncatedStream(InputStream in) throws IOException {
020: for (int i = 0; i != lookAhead.length; i++) {
021: lookAhead[i] = in.read();
022: }
023:
024: bufPtr = 0;
025: this .in = in;
026: }
027:
028: public int read() throws IOException {
029: int ch = in.read();
030:
031: if (ch >= 0) {
032: int c = lookAhead[bufPtr];
033:
034: lookAhead[bufPtr] = ch;
035: bufPtr = (bufPtr + 1) % lookAhead.length;
036:
037: return c;
038: }
039:
040: return -1;
041: }
042:
043: int[] getLookAhead() {
044: int[] tmp = new int[lookAhead.length];
045: int count = 0;
046:
047: for (int i = bufPtr; i != lookAhead.length; i++) {
048: tmp[count++] = lookAhead[i];
049: }
050: for (int i = 0; i != bufPtr; i++) {
051: tmp[count++] = lookAhead[i];
052: }
053:
054: return tmp;
055: }
056: }
057:
058: InputStreamPacket encData;
059: InputStream encStream;
060: TruncatedStream truncStream;
061:
062: PGPEncryptedData(InputStreamPacket encData) {
063: this .encData = encData;
064: }
065:
066: /**
067: * Return the raw input stream for the data stream.
068: *
069: * @return InputStream
070: */
071: public InputStream getInputStream() {
072: return encData.getInputStream();
073: }
074:
075: /**
076: * Return true if the message is integrity protected.
077: * @return true if there is a modification detection code package associated with this stream
078: */
079: public boolean isIntegrityProtected() {
080: return (encData instanceof SymmetricEncIntegrityPacket);
081: }
082:
083: /**
084: * Note: This can only be called after the message has been read.
085: *
086: * @return true if the message verifies, false otherwise.
087: * @throws PGPException if the message is not integrity protected.
088: */
089: public boolean verify() throws PGPException, IOException {
090: if (!this .isIntegrityProtected()) {
091: throw new PGPException("data not integrity protected.");
092: }
093:
094: DigestInputStream dIn = (DigestInputStream) encStream;
095:
096: //
097: // make sure we are at the end.
098: //
099: while (encStream.read() >= 0) {
100: // do nothing
101: }
102:
103: MessageDigest hash = dIn.getMessageDigest();
104:
105: //
106: // process the MDC packet
107: //
108: int[] lookAhead = truncStream.getLookAhead();
109:
110: hash.update((byte) lookAhead[0]);
111: hash.update((byte) lookAhead[1]);
112:
113: byte[] digest = hash.digest();
114: byte[] streamDigest = new byte[digest.length];
115:
116: for (int i = 0; i != streamDigest.length; i++) {
117: streamDigest[i] = (byte) lookAhead[i + 2];
118: }
119:
120: return MessageDigest.isEqual(digest, streamDigest);
121: }
122: }
|