001: package org.bouncycastle.openpgp;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.math.BigInteger;
005: import java.security.InvalidKeyException;
006: import java.security.MessageDigest;
007: import java.security.NoSuchAlgorithmException;
008: import java.security.NoSuchProviderException;
009: import java.security.Signature;
010: import java.security.SignatureException;
011: import java.util.Date;
012:
013: import org.bouncycastle.bcpg.MPInteger;
014: import org.bouncycastle.bcpg.OnePassSignaturePacket;
015: import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
016: import org.bouncycastle.bcpg.SignaturePacket;
017:
018: /**
019: * Generator for old style PGP V3 Signatures.
020: */
021: public class PGPV3SignatureGenerator {
022: private int keyAlgorithm;
023: private int hashAlgorithm;
024: private PGPPrivateKey privKey;
025: private Signature sig;
026: private MessageDigest dig;
027: private int signatureType;
028:
029: private byte lastb;
030:
031: /**
032: * Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.
033: *
034: * @param keyAlgorithm
035: * @param hashAlgorithm
036: * @param provider
037: * @throws NoSuchAlgorithmException
038: * @throws NoSuchProviderException
039: * @throws PGPException
040: */
041: public PGPV3SignatureGenerator(int keyAlgorithm, int hashAlgorithm,
042: String provider) throws NoSuchAlgorithmException,
043: NoSuchProviderException, PGPException {
044: this .keyAlgorithm = keyAlgorithm;
045: this .hashAlgorithm = hashAlgorithm;
046:
047: dig = PGPUtil.getDigestInstance(PGPUtil
048: .getDigestName(hashAlgorithm), provider);
049: sig = Signature.getInstance(PGPUtil.getSignatureName(
050: keyAlgorithm, hashAlgorithm), provider);
051: }
052:
053: /**
054: * Initialise the generator for signing.
055: *
056: * @param signatureType
057: * @param key
058: * @throws PGPException
059: */
060: public void initSign(int signatureType, PGPPrivateKey key)
061: throws PGPException {
062: this .privKey = key;
063: this .signatureType = signatureType;
064:
065: try {
066: sig.initSign(key.getKey());
067: } catch (InvalidKeyException e) {
068: throw new PGPException("invalid key.", e);
069: }
070:
071: dig.reset();
072: lastb = 0;
073: }
074:
075: public void update(byte b) throws SignatureException {
076: if (signatureType == PGPSignature.CANONICAL_TEXT_DOCUMENT) {
077: if (b == '\r') {
078: sig.update((byte) '\r');
079: sig.update((byte) '\n');
080: dig.update((byte) '\r');
081: dig.update((byte) '\n');
082: } else if (b == '\n') {
083: if (lastb != '\r') {
084: sig.update((byte) '\r');
085: sig.update((byte) '\n');
086: dig.update((byte) '\r');
087: dig.update((byte) '\n');
088: }
089: } else {
090: sig.update(b);
091: dig.update(b);
092: }
093:
094: lastb = b;
095: } else {
096: sig.update(b);
097: dig.update(b);
098: }
099: }
100:
101: public void update(byte[] b) throws SignatureException {
102: this .update(b, 0, b.length);
103: }
104:
105: public void update(byte[] b, int off, int len)
106: throws SignatureException {
107: if (signatureType == PGPSignature.CANONICAL_TEXT_DOCUMENT) {
108: int finish = off + len;
109:
110: for (int i = off; i != finish; i++) {
111: this .update(b[i]);
112: }
113: } else {
114: sig.update(b, off, len);
115: dig.update(b, off, len);
116: }
117: }
118:
119: /**
120: * Return the one pass header associated with the current signature.
121: *
122: * @param isNested
123: * @return PGPOnePassSignature
124: * @throws PGPException
125: */
126: public PGPOnePassSignature generateOnePassVersion(boolean isNested)
127: throws PGPException {
128: return new PGPOnePassSignature(new OnePassSignaturePacket(
129: signatureType, hashAlgorithm, keyAlgorithm, privKey
130: .getKeyID(), isNested));
131: }
132:
133: /**
134: * Return a V3 signature object containing the current signature state.
135: *
136: * @return PGPSignature
137: * @throws PGPException
138: * @throws SignatureException
139: */
140: public PGPSignature generate() throws PGPException,
141: SignatureException {
142: long creationTime = new Date().getTime() / 1000;
143:
144: ByteArrayOutputStream sOut = new ByteArrayOutputStream();
145:
146: sOut.write(signatureType);
147: sOut.write((byte) (creationTime >> 24));
148: sOut.write((byte) (creationTime >> 16));
149: sOut.write((byte) (creationTime >> 8));
150: sOut.write((byte) creationTime);
151:
152: byte[] hData = sOut.toByteArray();
153:
154: sig.update(hData);
155: dig.update(hData);
156:
157: MPInteger[] sigValues;
158: if (keyAlgorithm == PublicKeyAlgorithmTags.RSA_SIGN
159: || keyAlgorithm == PublicKeyAlgorithmTags.RSA_GENERAL)
160: // an RSA signature
161: {
162: sigValues = new MPInteger[1];
163: sigValues[0] = new MPInteger(new BigInteger(1, sig.sign()));
164: } else {
165: sigValues = PGPUtil.dsaSigToMpi(sig.sign());
166: }
167:
168: byte[] digest = dig.digest();
169: byte[] fingerPrint = new byte[2];
170:
171: fingerPrint[0] = digest[0];
172: fingerPrint[1] = digest[1];
173:
174: return new PGPSignature(new SignaturePacket(3, signatureType,
175: privKey.getKeyID(), keyAlgorithm, hashAlgorithm,
176: creationTime * 1000, fingerPrint, sigValues));
177: }
178: }
|