using System; using System.IO; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Bcpg.OpenPgp { /// A one pass signature object. public class PgpOnePassSignature { private OnePassSignaturePacket sigPack; private int signatureType; private ISigner sig; private byte lastb; internal PgpOnePassSignature( BcpgInputStream bcpgInput) : this((OnePassSignaturePacket) bcpgInput.ReadPacket()) { } internal PgpOnePassSignature( OnePassSignaturePacket sigPack) { this.sigPack = sigPack; this.signatureType = sigPack.SignatureType; } /// Initialise the signature object for verification. public void InitVerify( PgpPublicKey pubKey) { lastb = 0; try { sig = SignerUtilities.GetSigner( PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm)); } catch (Exception e) { throw new PgpException("can't set up signature object.", e); } try { sig.Init(false, pubKey.GetKey()); } catch (InvalidKeyException e) { throw new PgpException("invalid key.", e); } } public void Update( byte b) { if (signatureType == PgpSignature.CanonicalTextDocument) { doCanonicalUpdateByte(b); } else { sig.Update(b); } } private void doCanonicalUpdateByte( byte b) { if (b == '\r') { doUpdateCRLF(); } else if (b == '\n') { if (lastb != '\r') { doUpdateCRLF(); } } else { sig.Update(b); } lastb = b; } private void doUpdateCRLF() { sig.Update((byte)'\r'); sig.Update((byte)'\n'); } public void Update( byte[] bytes) { if (signatureType == PgpSignature.CanonicalTextDocument) { for (int i = 0; i != bytes.Length; i++) { doCanonicalUpdateByte(bytes[i]); } } else { sig.BlockUpdate(bytes, 0, bytes.Length); } } public void Update( byte[] bytes, int off, int length) { if (signatureType == PgpSignature.CanonicalTextDocument) { int finish = off + length; for (int i = off; i != finish; i++) { doCanonicalUpdateByte(bytes[i]); } } else { sig.BlockUpdate(bytes, off, length); } } /// Verify the calculated signature against the passed in PgpSignature. public bool Verify( PgpSignature pgpSig) { byte[] trailer = pgpSig.GetSignatureTrailer(); sig.BlockUpdate(trailer, 0, trailer.Length); return sig.VerifySignature(pgpSig.GetSignature()); } public long KeyId { get { return sigPack.KeyId; } } public int SignatureType { get { return sigPack.SignatureType; } } public HashAlgorithmTag HashAlgorithm { get { return sigPack.HashAlgorithm; } } public PublicKeyAlgorithmTag KeyAlgorithm { get { return sigPack.KeyAlgorithm; } } public byte[] GetEncoded() { MemoryStream bOut = new MemoryStream(); Encode(bOut); return bOut.ToArray(); } public void Encode( Stream outStr) { BcpgOutputStream.Wrap(outStr).WritePacket(sigPack); } } }