001: package org.bouncycastle.bcpg;
002:
003: import org.bouncycastle.bcpg.sig.IssuerKeyID;
004: import org.bouncycastle.bcpg.sig.SignatureCreationTime;
005: import org.bouncycastle.util.Arrays;
006:
007: import java.io.ByteArrayInputStream;
008: import java.io.ByteArrayOutputStream;
009: import java.io.IOException;
010: import java.util.Vector;
011:
012: /**
013: * generic signature packet
014: */
015: public class SignaturePacket extends ContainedPacket implements
016: PublicKeyAlgorithmTags {
017: private int version;
018: private int signatureType;
019: private long creationTime;
020: private long keyID;
021: private int keyAlgorithm;
022: private int hashAlgorithm;
023: private MPInteger[] signature;
024: private byte[] fingerPrint;
025: private SignatureSubpacket[] hashedData;
026: private SignatureSubpacket[] unhashedData;
027: private byte[] signatureEncoding;
028:
029: SignaturePacket(BCPGInputStream in) throws IOException {
030: version = in.read();
031:
032: if (version == 3 || version == 2) {
033: int l = in.read();
034:
035: signatureType = in.read();
036: creationTime = (((long) in.read() << 24)
037: | (in.read() << 16) | (in.read() << 8) | in.read()) * 1000;
038: keyID |= (long) in.read() << 56;
039: keyID |= (long) in.read() << 48;
040: keyID |= (long) in.read() << 40;
041: keyID |= (long) in.read() << 32;
042: keyID |= (long) in.read() << 24;
043: keyID |= (long) in.read() << 16;
044: keyID |= (long) in.read() << 8;
045: keyID |= in.read();
046: keyAlgorithm = in.read();
047: hashAlgorithm = in.read();
048: } else if (version == 4) {
049: signatureType = in.read();
050: keyAlgorithm = in.read();
051: hashAlgorithm = in.read();
052:
053: int hashedLength = (in.read() << 8) | in.read();
054: byte[] hashed = new byte[hashedLength];
055:
056: in.readFully(hashed);
057:
058: //
059: // read the signature sub packet data.
060: //
061: SignatureSubpacket sub;
062: SignatureSubpacketInputStream sIn = new SignatureSubpacketInputStream(
063: new ByteArrayInputStream(hashed));
064:
065: Vector v = new Vector();
066: while ((sub = sIn.readPacket()) != null) {
067: v.addElement(sub);
068: }
069:
070: hashedData = new SignatureSubpacket[v.size()];
071:
072: for (int i = 0; i != hashedData.length; i++) {
073: SignatureSubpacket p = (SignatureSubpacket) v
074: .elementAt(i);
075: if (p instanceof IssuerKeyID) {
076: keyID = ((IssuerKeyID) p).getKeyID();
077: } else if (p instanceof SignatureCreationTime) {
078: creationTime = ((SignatureCreationTime) p)
079: .getTime().getTime();
080: }
081:
082: hashedData[i] = p;
083: }
084:
085: int unhashedLength = (in.read() << 8) | in.read();
086: byte[] unhashed = new byte[unhashedLength];
087:
088: in.readFully(unhashed);
089:
090: sIn = new SignatureSubpacketInputStream(
091: new ByteArrayInputStream(unhashed));
092:
093: v.removeAllElements();
094: while ((sub = sIn.readPacket()) != null) {
095: v.addElement(sub);
096: }
097:
098: unhashedData = new SignatureSubpacket[v.size()];
099:
100: for (int i = 0; i != unhashedData.length; i++) {
101: SignatureSubpacket p = (SignatureSubpacket) v
102: .elementAt(i);
103: if (p instanceof IssuerKeyID) {
104: keyID = ((IssuerKeyID) p).getKeyID();
105: } else if (p instanceof SignatureCreationTime) {
106: creationTime = ((SignatureCreationTime) p)
107: .getTime().getTime();
108: }
109:
110: unhashedData[i] = p;
111: }
112: } else {
113: throw new RuntimeException("unsupported version: "
114: + version);
115: }
116:
117: fingerPrint = new byte[2];
118: in.readFully(fingerPrint);
119:
120: switch (keyAlgorithm) {
121: case RSA_GENERAL:
122: case RSA_SIGN:
123: MPInteger v = new MPInteger(in);
124:
125: signature = new MPInteger[1];
126: signature[0] = v;
127: break;
128: case DSA:
129: MPInteger r = new MPInteger(in);
130: MPInteger s = new MPInteger(in);
131:
132: signature = new MPInteger[2];
133: signature[0] = r;
134: signature[1] = s;
135: break;
136: case ELGAMAL_ENCRYPT: // yep, this really does happen sometimes.
137: case ELGAMAL_GENERAL:
138: MPInteger p = new MPInteger(in);
139: MPInteger g = new MPInteger(in);
140: MPInteger y = new MPInteger(in);
141:
142: signature = new MPInteger[3];
143: signature[0] = p;
144: signature[1] = g;
145: signature[2] = y;
146: break;
147: default:
148: if (keyAlgorithm >= PublicKeyAlgorithmTags.EXPERIMENTAL_1
149: && keyAlgorithm <= PublicKeyAlgorithmTags.EXPERIMENTAL_11) {
150: signature = null;
151: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
152: int ch;
153: while ((ch = in.read()) >= 0) {
154: bOut.write(ch);
155: }
156: signatureEncoding = bOut.toByteArray();
157: } else {
158: throw new IOException(
159: "unknown signature key algorithm: "
160: + keyAlgorithm);
161: }
162: }
163: }
164:
165: /**
166: * Generate a version 4 signature packet.
167: *
168: * @param signatureType
169: * @param keyAlgorithm
170: * @param hashAlgorithm
171: * @param hashedData
172: * @param unhashedData
173: * @param fingerPrint
174: * @param signature
175: */
176: public SignaturePacket(int signatureType, long keyID,
177: int keyAlgorithm, int hashAlgorithm,
178: SignatureSubpacket[] hashedData,
179: SignatureSubpacket[] unhashedData, byte[] fingerPrint,
180: MPInteger[] signature) {
181: this (4, signatureType, keyID, keyAlgorithm, hashAlgorithm,
182: hashedData, unhashedData, fingerPrint, signature);
183: }
184:
185: /**
186: * Generate a version 2/3 signature packet.
187: *
188: * @param signatureType
189: * @param keyAlgorithm
190: * @param hashAlgorithm
191: * @param fingerPrint
192: * @param signature
193: */
194: public SignaturePacket(int version, int signatureType, long keyID,
195: int keyAlgorithm, int hashAlgorithm, long creationTime,
196: byte[] fingerPrint, MPInteger[] signature) {
197: this (version, signatureType, keyID, keyAlgorithm,
198: hashAlgorithm, null, null, fingerPrint, signature);
199:
200: this .creationTime = creationTime;
201: }
202:
203: public SignaturePacket(int version, int signatureType, long keyID,
204: int keyAlgorithm, int hashAlgorithm,
205: SignatureSubpacket[] hashedData,
206: SignatureSubpacket[] unhashedData, byte[] fingerPrint,
207: MPInteger[] signature) {
208: this .version = version;
209: this .signatureType = signatureType;
210: this .keyID = keyID;
211: this .keyAlgorithm = keyAlgorithm;
212: this .hashAlgorithm = hashAlgorithm;
213: this .hashedData = hashedData;
214: this .unhashedData = unhashedData;
215: this .fingerPrint = fingerPrint;
216: this .signature = signature;
217: }
218:
219: /**
220: * get the version number
221: */
222: public int getVersion() {
223: return version;
224: }
225:
226: /**
227: * return the signature type.
228: */
229: public int getSignatureType() {
230: return signatureType;
231: }
232:
233: /**
234: * return the keyID
235: * @return the keyID that created the signature.
236: */
237: public long getKeyID() {
238: return keyID;
239: }
240:
241: /**
242: * return the signature trailer that must be included with the data
243: * to reconstruct the signature
244: *
245: * @return byte[]
246: */
247: public byte[] getSignatureTrailer() {
248: byte[] trailer = null;
249:
250: if (version == 3 || version == 2) {
251: trailer = new byte[5];
252:
253: long time = creationTime / 1000;
254:
255: trailer[0] = (byte) signatureType;
256: trailer[1] = (byte) (time >> 24);
257: trailer[2] = (byte) (time >> 16);
258: trailer[3] = (byte) (time >> 8);
259: trailer[4] = (byte) (time);
260: } else {
261: ByteArrayOutputStream sOut = new ByteArrayOutputStream();
262:
263: try {
264: sOut.write((byte) this .getVersion());
265: sOut.write((byte) this .getSignatureType());
266: sOut.write((byte) this .getKeyAlgorithm());
267: sOut.write((byte) this .getHashAlgorithm());
268:
269: ByteArrayOutputStream hOut = new ByteArrayOutputStream();
270: SignatureSubpacket[] hashed = this
271: .getHashedSubPackets();
272:
273: for (int i = 0; i != hashed.length; i++) {
274: hashed[i].encode(hOut);
275: }
276:
277: byte[] data = hOut.toByteArray();
278:
279: sOut.write((byte) (data.length >> 8));
280: sOut.write((byte) data.length);
281: sOut.write(data);
282:
283: byte[] hData = sOut.toByteArray();
284:
285: sOut.write((byte) this .getVersion());
286: sOut.write((byte) 0xff);
287: sOut.write((byte) (hData.length >> 24));
288: sOut.write((byte) (hData.length >> 16));
289: sOut.write((byte) (hData.length >> 8));
290: sOut.write((byte) (hData.length));
291: } catch (IOException e) {
292: throw new RuntimeException(
293: "exception generating trailer: " + e);
294: }
295:
296: trailer = sOut.toByteArray();
297: }
298:
299: return trailer;
300: }
301:
302: /**
303: * return the encryption algorithm tag
304: */
305: public int getKeyAlgorithm() {
306: return keyAlgorithm;
307: }
308:
309: /**
310: * return the hashAlgorithm tag
311: */
312: public int getHashAlgorithm() {
313: return hashAlgorithm;
314: }
315:
316: /**
317: * return the signature as a set of integers - note this is normalised to be the
318: * ASN.1 encoding of what appears in the signature packet.
319: */
320: public MPInteger[] getSignature() {
321: return signature;
322: }
323:
324: /**
325: * Return the byte encoding of the signature section.
326: * @return uninterpreted signature bytes.
327: */
328: public byte[] getSignatureBytes() {
329: if (signatureEncoding == null) {
330: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
331: BCPGOutputStream bcOut = new BCPGOutputStream(bOut);
332:
333: for (int i = 0; i != signature.length; i++) {
334: try {
335: bcOut.writeObject(signature[i]);
336: } catch (IOException e) {
337: throw new RuntimeException("internal error: " + e);
338: }
339: }
340: return bOut.toByteArray();
341: } else {
342: return Arrays.clone(signatureEncoding);
343: }
344: }
345:
346: public SignatureSubpacket[] getHashedSubPackets() {
347: return hashedData;
348: }
349:
350: public SignatureSubpacket[] getUnhashedSubPackets() {
351: return unhashedData;
352: }
353:
354: /**
355: * Return the creation time of the signature in milli-seconds.
356: *
357: * @return the creation time in millis
358: */
359: public long getCreationTime() {
360: return creationTime;
361: }
362:
363: public void encode(BCPGOutputStream out) throws IOException {
364: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
365: BCPGOutputStream pOut = new BCPGOutputStream(bOut);
366:
367: pOut.write(version);
368:
369: if (version == 3 || version == 2) {
370: pOut.write(5); // the length of the next block
371:
372: long time = creationTime / 1000;
373:
374: pOut.write(signatureType);
375: pOut.write((byte) (time >> 24));
376: pOut.write((byte) (time >> 16));
377: pOut.write((byte) (time >> 8));
378: pOut.write((byte) time);
379:
380: pOut.write((byte) (keyID >> 56));
381: pOut.write((byte) (keyID >> 48));
382: pOut.write((byte) (keyID >> 40));
383: pOut.write((byte) (keyID >> 32));
384: pOut.write((byte) (keyID >> 24));
385: pOut.write((byte) (keyID >> 16));
386: pOut.write((byte) (keyID >> 8));
387: pOut.write((byte) (keyID));
388:
389: pOut.write(keyAlgorithm);
390: pOut.write(hashAlgorithm);
391: } else if (version == 4) {
392: pOut.write(signatureType);
393: pOut.write(keyAlgorithm);
394: pOut.write(hashAlgorithm);
395:
396: ByteArrayOutputStream sOut = new ByteArrayOutputStream();
397:
398: for (int i = 0; i != hashedData.length; i++) {
399: hashedData[i].encode(sOut);
400: }
401:
402: byte[] data = sOut.toByteArray();
403:
404: pOut.write(data.length >> 8);
405: pOut.write(data.length);
406: pOut.write(data);
407:
408: sOut.reset();
409:
410: for (int i = 0; i != unhashedData.length; i++) {
411: unhashedData[i].encode(sOut);
412: }
413:
414: data = sOut.toByteArray();
415:
416: pOut.write(data.length >> 8);
417: pOut.write(data.length);
418: pOut.write(data);
419: } else {
420: throw new IOException("unknown version: " + version);
421: }
422:
423: pOut.write(fingerPrint);
424:
425: if (signature != null) {
426: for (int i = 0; i != signature.length; i++) {
427: pOut.writeObject(signature[i]);
428: }
429: } else {
430: pOut.write(signatureEncoding);
431: }
432:
433: out.writePacket(SIGNATURE, bOut.toByteArray(), true);
434: }
435: }
|