package org.spongycastle.openpgp; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.SignatureException; import org.spongycastle.bcpg.BCPGInputStream; import org.spongycastle.bcpg.BCPGOutputStream; import org.spongycastle.bcpg.OnePassSignaturePacket; import org.spongycastle.openpgp.operator.PGPContentVerifier; import org.spongycastle.openpgp.operator.PGPContentVerifierBuilder; import org.spongycastle.openpgp.operator.PGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; /** * A one pass signature object. */ public class PGPOnePassSignature { private OnePassSignaturePacket sigPack; private int signatureType; private PGPContentVerifier verifier; private byte lastb; private OutputStream sigOut; PGPOnePassSignature( BCPGInputStream pIn) throws IOException, PGPException { this((OnePassSignaturePacket)pIn.readPacket()); } PGPOnePassSignature( OnePassSignaturePacket sigPack) throws PGPException { this.sigPack = sigPack; this.signatureType = sigPack.getSignatureType(); } /** * Initialise the signature object for verification. * * @param pubKey * @param provider * @throws NoSuchProviderException * @throws PGPException * @deprecated use init() method. */ public void initVerify( PGPPublicKey pubKey, String provider) throws NoSuchProviderException, PGPException { initVerify(pubKey, PGPUtil.getProvider(provider)); } /** * Initialise the signature object for verification. * * @param pubKey * @param provider * @throws NoSuchProviderException * @throws PGPException * @deprecated use init() method. */ public void initVerify( PGPPublicKey pubKey, Provider provider) throws PGPException { init(new JcaPGPContentVerifierBuilderProvider().setProvider(provider), pubKey); } /** * Initialise the signature object for verification. * * @param verifierBuilderProvider provider for a content verifier builder for the signature type of interest. * @param pubKey the public key to use for verification * @throws PGPException if there's an issue with creating the verifier. */ public void init(PGPContentVerifierBuilderProvider verifierBuilderProvider, PGPPublicKey pubKey) throws PGPException { PGPContentVerifierBuilder verifierBuilder = verifierBuilderProvider.get(sigPack.getKeyAlgorithm(), sigPack.getHashAlgorithm()); verifier = verifierBuilder.build(pubKey); lastb = 0; sigOut = verifier.getOutputStream(); } public void update( byte b) throws SignatureException { if (signatureType == 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[] bytes) throws SignatureException { if (signatureType == PGPSignature.CANONICAL_TEXT_DOCUMENT) { for (int i = 0; i != bytes.length; i++) { this.update(bytes[i]); } } else { blockUpdate(bytes, 0, bytes.length); } } public void update( byte[] bytes, int off, int length) throws SignatureException { if (signatureType == PGPSignature.CANONICAL_TEXT_DOCUMENT) { int finish = off + length; for (int i = off; i != finish; i++) { this.update(bytes[i]); } } else { blockUpdate(bytes, off, length); } } private void byteUpdate(byte b) throws SignatureException { try { sigOut.write(b); } catch (IOException e) { // TODO: we really should get rid of signature exception next.... throw new SignatureException(e.getMessage()); } } private void blockUpdate(byte[] block, int off, int len) throws SignatureException { try { sigOut.write(block, off, len); } catch (IOException e) { throw new IllegalStateException(e.getMessage()); } } /** * Verify the calculated signature against the passed in PGPSignature. * * @param pgpSig * @return boolean * @throws PGPException * @throws SignatureException */ public boolean verify( PGPSignature pgpSig) throws PGPException, SignatureException { try { sigOut.write(pgpSig.getSignatureTrailer()); sigOut.close(); } catch (IOException e) { throw new PGPException("unable to add trailer: " + e.getMessage(), e); } return verifier.verify(pgpSig.getSignature()); } public long getKeyID() { return sigPack.getKeyID(); } public int getSignatureType() { return sigPack.getSignatureType(); } public int getHashAlgorithm() { return sigPack.getHashAlgorithm(); } public int getKeyAlgorithm() { return sigPack.getKeyAlgorithm(); } public byte[] getEncoded() throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); this.encode(bOut); return bOut.toByteArray(); } public void encode( OutputStream outStream) throws IOException { BCPGOutputStream out; if (outStream instanceof BCPGOutputStream) { out = (BCPGOutputStream)outStream; } else { out = new BCPGOutputStream(outStream); } out.writePacket(sigPack); } }