diff options
Diffstat (limited to 'pg/src/main/java/org/spongycastle/openpgp/PGPV3SignatureGenerator.java')
-rw-r--r-- | pg/src/main/java/org/spongycastle/openpgp/PGPV3SignatureGenerator.java | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/pg/src/main/java/org/spongycastle/openpgp/PGPV3SignatureGenerator.java b/pg/src/main/java/org/spongycastle/openpgp/PGPV3SignatureGenerator.java new file mode 100644 index 00000000..cb6cb921 --- /dev/null +++ b/pg/src/main/java/org/spongycastle/openpgp/PGPV3SignatureGenerator.java @@ -0,0 +1,201 @@ +package org.spongycastle.openpgp; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Date; + +import org.spongycastle.bcpg.MPInteger; +import org.spongycastle.bcpg.OnePassSignaturePacket; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SignaturePacket; +import org.spongycastle.openpgp.operator.PGPContentSigner; +import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; + +/** + * Generator for old style PGP V3 Signatures. + */ +public class PGPV3SignatureGenerator +{ + private byte lastb; + private OutputStream sigOut; + private PGPContentSignerBuilder contentSignerBuilder; + private PGPContentSigner contentSigner; + private int sigType; + private int providedKeyAlgorithm = -1; + + /** + * Create a signature generator built on the passed in contentSignerBuilder. + * + * @param contentSignerBuilder builder to produce PGPContentSigner objects for generating signatures. + */ + public PGPV3SignatureGenerator( + PGPContentSignerBuilder contentSignerBuilder) + { + this.contentSignerBuilder = contentSignerBuilder; + } + + /** + * Initialise the generator for signing. + * + * @param signatureType + * @param key + * @throws PGPException + */ + public void init( + int signatureType, + PGPPrivateKey key) + throws PGPException + { + contentSigner = contentSignerBuilder.build(signatureType, key); + sigOut = contentSigner.getOutputStream(); + sigType = contentSigner.getType(); + lastb = 0; + + if (providedKeyAlgorithm >= 0 && providedKeyAlgorithm != contentSigner.getKeyAlgorithm()) + { + throw new PGPException("key algorithm mismatch"); + } + } + + public void update( + byte b) + { + if (sigType == PGPSignature.CANONICAL_TEXT_DOCUMENT) + { + if (b == '\r') + { + byteUpdate((byte)'\r'); + byteUpdate((byte)'\n'); + } + else if (b == '\n') + { + if (lastb != '\r') + { + byteUpdate((byte)'\r'); + byteUpdate((byte)'\n'); + } + } + else + { + byteUpdate(b); + } + + lastb = b; + } + else + { + byteUpdate(b); + } + } + + public void update( + byte[] b) + { + this.update(b, 0, b.length); + } + + public void update( + byte[] b, + int off, + int len) + { + if (sigType == PGPSignature.CANONICAL_TEXT_DOCUMENT) + { + int finish = off + len; + + for (int i = off; i != finish; i++) + { + this.update(b[i]); + } + } + else + { + blockUpdate(b, off, len); + } + } + + private void byteUpdate(byte b) + { + try + { + sigOut.write(b); + } + catch (IOException e) + { + throw new PGPRuntimeOperationException("unable to update signature: " + e.getMessage(), e); + } + } + + private void blockUpdate(byte[] block, int off, int len) + { + try + { + sigOut.write(block, off, len); + } + catch (IOException e) + { + throw new PGPRuntimeOperationException("unable to update signature: " + e.getMessage(), e); + } + } + + /** + * Return the one pass header associated with the current signature. + * + * @param isNested + * @return PGPOnePassSignature + * @throws PGPException + */ + public PGPOnePassSignature generateOnePassVersion( + boolean isNested) + throws PGPException + { + return new PGPOnePassSignature(new OnePassSignaturePacket(sigType, contentSigner.getHashAlgorithm(), contentSigner.getKeyAlgorithm(), contentSigner.getKeyID(), isNested)); + } + + /** + * Return a V3 signature object containing the current signature state. + * + * @return PGPSignature + * @throws PGPException + */ + public PGPSignature generate() + throws PGPException + { + long creationTime = new Date().getTime() / 1000; + + ByteArrayOutputStream sOut = new ByteArrayOutputStream(); + + sOut.write(sigType); + sOut.write((byte)(creationTime >> 24)); + sOut.write((byte)(creationTime >> 16)); + sOut.write((byte)(creationTime >> 8)); + sOut.write((byte)creationTime); + + byte[] hData = sOut.toByteArray(); + + blockUpdate(hData, 0, hData.length); + + MPInteger[] sigValues; + if (contentSigner.getKeyAlgorithm() == PublicKeyAlgorithmTags.RSA_SIGN + || contentSigner.getKeyAlgorithm() == PublicKeyAlgorithmTags.RSA_GENERAL) + // an RSA signature + { + sigValues = new MPInteger[1]; + sigValues[0] = new MPInteger(new BigInteger(1, contentSigner.getSignature())); + } + else + { + sigValues = PGPUtil.dsaSigToMpi(contentSigner.getSignature()); + } + + byte[] digest = contentSigner.getDigest(); + byte[] fingerPrint = new byte[2]; + + fingerPrint[0] = digest[0]; + fingerPrint[1] = digest[1]; + + return new PGPSignature(new SignaturePacket(3, contentSigner.getType(), contentSigner.getKeyID(), contentSigner.getKeyAlgorithm(), contentSigner.getHashAlgorithm(), creationTime * 1000, fingerPrint, sigValues)); + } +} |