Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pg/src/main/java/org/spongycastle/openpgp/PGPSignature.java')
-rw-r--r--pg/src/main/java/org/spongycastle/openpgp/PGPSignature.java559
1 files changed, 559 insertions, 0 deletions
diff --git a/pg/src/main/java/org/spongycastle/openpgp/PGPSignature.java b/pg/src/main/java/org/spongycastle/openpgp/PGPSignature.java
new file mode 100644
index 00000000..b58a667e
--- /dev/null
+++ b/pg/src/main/java/org/spongycastle/openpgp/PGPSignature.java
@@ -0,0 +1,559 @@
+package org.spongycastle.openpgp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.bcpg.BCPGInputStream;
+import org.spongycastle.bcpg.BCPGOutputStream;
+import org.spongycastle.bcpg.MPInteger;
+import org.spongycastle.bcpg.SignaturePacket;
+import org.spongycastle.bcpg.SignatureSubpacket;
+import org.spongycastle.bcpg.TrustPacket;
+import org.spongycastle.bcpg.UserAttributeSubpacket;
+import org.spongycastle.openpgp.operator.PGPContentVerifier;
+import org.spongycastle.openpgp.operator.PGPContentVerifierBuilder;
+import org.spongycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
+import org.spongycastle.util.BigIntegers;
+import org.spongycastle.util.Strings;
+
+/**
+ *A PGP signature object.
+ */
+public class PGPSignature
+{
+ public static final int BINARY_DOCUMENT = 0x00;
+ public static final int CANONICAL_TEXT_DOCUMENT = 0x01;
+ public static final int STAND_ALONE = 0x02;
+
+ public static final int DEFAULT_CERTIFICATION = 0x10;
+ public static final int NO_CERTIFICATION = 0x11;
+ public static final int CASUAL_CERTIFICATION = 0x12;
+ public static final int POSITIVE_CERTIFICATION = 0x13;
+
+ public static final int SUBKEY_BINDING = 0x18;
+ public static final int PRIMARYKEY_BINDING = 0x19;
+ public static final int DIRECT_KEY = 0x1f;
+ public static final int KEY_REVOCATION = 0x20;
+ public static final int SUBKEY_REVOCATION = 0x28;
+ public static final int CERTIFICATION_REVOCATION = 0x30;
+ public static final int TIMESTAMP = 0x40;
+
+ private SignaturePacket sigPck;
+ private int signatureType;
+ private TrustPacket trustPck;
+ private PGPContentVerifier verifier;
+ private byte lastb;
+ private OutputStream sigOut;
+
+ PGPSignature(
+ BCPGInputStream pIn)
+ throws IOException, PGPException
+ {
+ this((SignaturePacket)pIn.readPacket());
+ }
+
+ PGPSignature(
+ SignaturePacket sigPacket)
+ throws PGPException
+ {
+ sigPck = sigPacket;
+ signatureType = sigPck.getSignatureType();
+ trustPck = null;
+ }
+
+ PGPSignature(
+ SignaturePacket sigPacket,
+ TrustPacket trustPacket)
+ throws PGPException
+ {
+ this(sigPacket);
+
+ this.trustPck = trustPacket;
+ }
+
+ /**
+ * Return the OpenPGP version number for this signature.
+ *
+ * @return signature version number.
+ */
+ public int getVersion()
+ {
+ return sigPck.getVersion();
+ }
+
+ /**
+ * Return the key algorithm associated with this signature.
+ * @return signature key algorithm.
+ */
+ public int getKeyAlgorithm()
+ {
+ return sigPck.getKeyAlgorithm();
+ }
+
+ /**
+ * Return the hash algorithm associated with this signature.
+ * @return signature hash algorithm.
+ */
+ public int getHashAlgorithm()
+ {
+ return sigPck.getHashAlgorithm();
+ }
+
+ public void init(PGPContentVerifierBuilderProvider verifierBuilderProvider, PGPPublicKey pubKey)
+ throws PGPException
+ {
+ PGPContentVerifierBuilder verifierBuilder = verifierBuilderProvider.get(sigPck.getKeyAlgorithm(), sigPck.getHashAlgorithm());
+
+ verifier = verifierBuilder.build(pubKey);
+
+ lastb = 0;
+ sigOut = verifier.getOutputStream();
+ }
+
+ public void update(
+ byte b)
+ {
+ 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)
+ {
+ this.update(bytes, 0, bytes.length);
+ }
+
+ public void update(
+ byte[] bytes,
+ int off,
+ int length)
+ {
+ 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)
+ {
+ try
+ {
+ sigOut.write(b);
+ }
+ catch (IOException e)
+ {
+ throw new PGPRuntimeOperationException(e.getMessage(), e);
+ }
+ }
+
+ private void blockUpdate(byte[] block, int off, int len)
+ {
+ try
+ {
+ sigOut.write(block, off, len);
+ }
+ catch (IOException e)
+ {
+ throw new PGPRuntimeOperationException(e.getMessage(), e);
+ }
+ }
+
+ public boolean verify()
+ throws PGPException
+ {
+ try
+ {
+ sigOut.write(this.getSignatureTrailer());
+
+ sigOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
+
+ return verifier.verify(this.getSignature());
+ }
+
+
+ private void updateWithIdData(int header, byte[] idBytes)
+ {
+ this.update((byte)header);
+ this.update((byte)(idBytes.length >> 24));
+ this.update((byte)(idBytes.length >> 16));
+ this.update((byte)(idBytes.length >> 8));
+ this.update((byte)(idBytes.length));
+ this.update(idBytes);
+ }
+
+ private void updateWithPublicKey(PGPPublicKey key)
+ throws PGPException
+ {
+ byte[] keyBytes = getEncodedPublicKey(key);
+
+ this.update((byte)0x99);
+ this.update((byte)(keyBytes.length >> 8));
+ this.update((byte)(keyBytes.length));
+ this.update(keyBytes);
+ }
+
+ /**
+ * Verify the signature as certifying the passed in public key as associated
+ * with the passed in user attributes.
+ *
+ * @param userAttributes user attributes the key was stored under
+ * @param key the key to be verified.
+ * @return true if the signature matches, false otherwise.
+ * @throws PGPException
+ */
+ public boolean verifyCertification(
+ PGPUserAttributeSubpacketVector userAttributes,
+ PGPPublicKey key)
+ throws PGPException
+ {
+ if (verifier == null)
+ {
+ throw new PGPException("PGPSignature not initialised - call init().");
+ }
+
+ updateWithPublicKey(key);
+
+ //
+ // hash in the userAttributes
+ //
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ UserAttributeSubpacket[] packets = userAttributes.toSubpacketArray();
+ for (int i = 0; i != packets.length; i++)
+ {
+ packets[i].encode(bOut);
+ }
+ updateWithIdData(0xd1, bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new PGPException("cannot encode subpacket array", e);
+ }
+
+ addTrailer();
+
+ return verifier.verify(this.getSignature());
+ }
+
+ /**
+ * Verify the signature as certifying the passed in public key as associated
+ * with the passed in id.
+ *
+ * @param id id the key was stored under
+ * @param key the key to be verified.
+ * @return true if the signature matches, false otherwise.
+ * @throws PGPException
+ */
+ public boolean verifyCertification(
+ String id,
+ PGPPublicKey key)
+ throws PGPException
+ {
+ if (verifier == null)
+ {
+ throw new PGPException("PGPSignature not initialised - call init().");
+ }
+
+ updateWithPublicKey(key);
+
+ //
+ // hash in the id
+ //
+ updateWithIdData(0xb4, Strings.toUTF8ByteArray(id));
+
+ addTrailer();
+
+ return verifier.verify(this.getSignature());
+ }
+
+ /**
+ * Verify the signature as certifying the passed in public key as associated
+ * with the passed in rawID.
+ *
+ * @param rawID id the key was stored under in its raw byte form.
+ * @param key the key to be verified.
+ * @return true if the signature matches, false otherwise.
+ * @throws PGPException
+ */
+ public boolean verifyCertification(
+ byte[] rawID,
+ PGPPublicKey key)
+ throws PGPException
+ {
+ if (verifier == null)
+ {
+ throw new PGPException("PGPSignature not initialised - call init().");
+ }
+
+ updateWithPublicKey(key);
+
+ //
+ // hash in the rawID
+ //
+ updateWithIdData(0xb4, rawID);
+
+ addTrailer();
+
+ return verifier.verify(this.getSignature());
+ }
+
+ /**
+ * Verify a certification for the passed in key against the passed in
+ * master key.
+ *
+ * @param masterKey the key we are verifying against.
+ * @param pubKey the key we are verifying.
+ * @return true if the certification is valid, false otherwise.
+ * @throws PGPException
+ */
+ public boolean verifyCertification(
+ PGPPublicKey masterKey,
+ PGPPublicKey pubKey)
+ throws PGPException
+ {
+ if (verifier == null)
+ {
+ throw new PGPException("PGPSignature not initialised - call init().");
+ }
+
+ updateWithPublicKey(masterKey);
+ updateWithPublicKey(pubKey);
+
+ addTrailer();
+
+ return verifier.verify(this.getSignature());
+ }
+
+ private void addTrailer()
+ {
+ try
+ {
+ sigOut.write(sigPck.getSignatureTrailer());
+
+ sigOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new PGPRuntimeOperationException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Verify a key certification, such as a revocation, for the passed in key.
+ *
+ * @param pubKey the key we are checking.
+ * @return true if the certification is valid, false otherwise.
+ * @throws PGPException
+ */
+ public boolean verifyCertification(
+ PGPPublicKey pubKey)
+ throws PGPException
+ {
+ if (verifier == null)
+ {
+ throw new PGPException("PGPSignature not initialised - call init().");
+ }
+
+ if (this.getSignatureType() != KEY_REVOCATION
+ && this.getSignatureType() != SUBKEY_REVOCATION
+ && this.getSignatureType() != DIRECT_KEY)
+ {
+ throw new PGPException("signature is not a key signature");
+ }
+
+ updateWithPublicKey(pubKey);
+
+ addTrailer();
+
+ return verifier.verify(this.getSignature());
+ }
+
+ public int getSignatureType()
+ {
+ return sigPck.getSignatureType();
+ }
+
+ /**
+ * Return the id of the key that created the signature.
+ * @return keyID of the signatures corresponding key.
+ */
+ public long getKeyID()
+ {
+ return sigPck.getKeyID();
+ }
+
+ /**
+ * Return the creation time of the signature.
+ *
+ * @return the signature creation time.
+ */
+ public Date getCreationTime()
+ {
+ return new Date(sigPck.getCreationTime());
+ }
+
+ public byte[] getSignatureTrailer()
+ {
+ return sigPck.getSignatureTrailer();
+ }
+
+ /**
+ * Return true if the signature has either hashed or unhashed subpackets.
+ *
+ * @return true if either hashed or unhashed subpackets are present, false otherwise.
+ */
+ public boolean hasSubpackets()
+ {
+ return sigPck.getHashedSubPackets() != null || sigPck.getUnhashedSubPackets() != null;
+ }
+
+ public PGPSignatureSubpacketVector getHashedSubPackets()
+ {
+ return createSubpacketVector(sigPck.getHashedSubPackets());
+ }
+
+ public PGPSignatureSubpacketVector getUnhashedSubPackets()
+ {
+ return createSubpacketVector(sigPck.getUnhashedSubPackets());
+ }
+
+ private PGPSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks)
+ {
+ if (pcks != null)
+ {
+ return new PGPSignatureSubpacketVector(pcks);
+ }
+
+ return null;
+ }
+
+ public byte[] getSignature()
+ throws PGPException
+ {
+ MPInteger[] sigValues = sigPck.getSignature();
+ byte[] signature;
+
+ if (sigValues != null)
+ {
+ if (sigValues.length == 1) // an RSA signature
+ {
+ signature = BigIntegers.asUnsignedByteArray(sigValues[0].getValue());
+ }
+ else
+ {
+ try
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ v.add(new ASN1Integer(sigValues[0].getValue()));
+ v.add(new ASN1Integer(sigValues[1].getValue()));
+
+ signature = new DERSequence(v).getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new PGPException("exception encoding DSA sig.", e);
+ }
+ }
+ }
+ else
+ {
+ signature = sigPck.getSignatureBytes();
+ }
+
+ return signature;
+ }
+
+ 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(sigPck);
+ if (trustPck != null)
+ {
+ out.writePacket(trustPck);
+ }
+ }
+
+ private byte[] getEncodedPublicKey(
+ PGPPublicKey pubKey)
+ throws PGPException
+ {
+ byte[] keyBytes;
+
+ try
+ {
+ keyBytes = pubKey.publicPk.getEncodedContents();
+ }
+ catch (IOException e)
+ {
+ throw new PGPException("exception preparing key.", e);
+ }
+
+ return keyBytes;
+ }
+}