Adding a Digital Signature to a PDF in Android

PSPDFKit enables signing both existing signature form elements and documents without a signature form element.

ℹ️ Note: If you want to use the Digital Signatures feature, make sure to include it in your license. Please follow this link to contact sales to start using it.

Creating a Digital Signature

Adding a digital signature on a PDF document is both reliable proof of the document’s origin and protection against modification by third parties.

To create a digital signature, you need two things.

  • First, you need an X509 certificate that contains your public key and your signer information. PSPDFKit supports PEM-encoded and DER-encoded X509 certificates, as well as DER-encoded PKCS#7 certificates. You can check the encoding of a certificate file by using the OpenSSL command-line tool as follows:

  openssl pkcs7 -noout -text -print_certs -in example.p7b

The above command will print an error message if “example.p7b” is not a PEM-encoded PKCS#7 certificate or certificate chain.

To verify if a PKCS#7 certificate file is correctly DER encoded, you can use this command instead:

  openssl pkcs7 -inform der -noout -text -print_certs -in example.p7b

The above command will print an error message if “example.p7b” is not a DER-encoded PKCS#7 certificate or certificate chain.

  • Second, you need your private key.

Signing Process

The signing process produces the signature by encrypting the message digest from the PDF file with a private key. The certificate with its public key is added to the signature and saved in the PDF file. The Signer class allows signing of documents by adding a digital signature to a SignatureFormField. Its methods, signFormField() and signFormFieldAsync(), allow both computation and saving of digital signatures to a definable output file.

PSPDFKit ships two default implementations of the Signer class, but you can always create a custom signer if your use case requires it. The two signers are:

  • MemorySigner, which takes a KeyStore.PrivateKeyEntry that was loaded by your app and uses it to sign the document directly.

  • Pkcs12Signer, which loads the signing certificate from a PKCS#12 file (usually having the .p12 file extension) to sign the document. If necessary, the signer will request a password for unlocking the PKCS#12 file to load the required keys from it:

// Create a signer loading the signing certificate from a PKCS#12 file.
// The provided `displayName` can be used by PSPDFKit in various views.
val signer: Signer = Pkcs12Signer(
	"John Appleseed",
	Uri.parse("file:///android_asset/JohnAppleseed.p12")
)

// Sign the form field, writing the signed document to a destination.
// You can optionally provide additional biometric signature data.
signer.signFormField(
	formField,
	biometricSignatureData,
	destination,
	object : Signer.OnSigningCompleteCallback() {
		override fun onSigningFailed(ex: Exception) {
			// Handle signing errors here...
		}

		override fun onSigningCompleted() {
			// The document was successfully signed!
		}
	}
);
// Create a signer loading the signing certificate from a PKCS#12 file.
// The provided `displayName` can be used by PSPDFKit in various views.
final Signer signer = new Pkcs12Signer(
	"John Appleseed",
	Uri.parse("file:///android_asset/JohnAppleseed.p12")
);

// Sign the form field, writing the signed document to a destination.
// You can optionally provide additional biometric signature data.
signer.signFormField(
	formField,
	biometricSignatureData,
	destination,
	new Signer.OnSigningCompleteCallback() {
		@Override
		public void onSigningFailed(Exception ex) {
			if (!e.isDisposed()) e.onError(ex);
		}

		@Override
		public void onSigningCompleted() {
			if (!e.isDisposed()) e.onComplete();
		}
	}
);

💡 Tip: For an interactive example of digital signatures, check out DigitalSignatureExample in the Catalog app.

Implementing the Custom Signature Provider

The SignatureProvider interface defines entities capable of signing data of a PDF. A custom signature provider has to implement two methods:

  • getEncryptionAlgorithm() has to return the encryption algorithm that will be applied to sign the PDF. The signature provider can return any of the available EncryptionAlgorithm values. Usually this is dependent on the private key used (i.e. whether you use an RSA or DSA key).

  • signData() has to perform the actual signing operation. This involves digesting the given PDF data using the requested HashAlgorithm and then encrypting it using the signer’s private key (using the selected encryption algorithm).

class CustomSignatureProvider: SignatureProvider {
	/**
	 * For example, this uses Java's crypto APIs for signing a PDF.
	 * The `getSignatureAlgorithm()` method will find the appropriate
	 * signing algorithm. You can see this example in our Catalog app.
	 */
	override fun signData(data: ByteArray, hashAlgorithm: HashAlgorithm): ByteArray
		= Signature.getInstance(getSignatureAlgorithm(hashAlgorithm)).run {
			initSign(signingKey.privateKey)
			update(data)
			sign()
		}

	override fun getEncryptionAlgorithm() = EncryptionAlgorithm.RSA
}
public class CustomSignatureProvider implements SignatureProvider {
	/**
	 * For example, this uses Java's crypto APIs for signing a PDF.
	 * The `getSignatureAlgorithm()` method will find the appropriate
	 * signing algorithm. You can see this example in our Catalog app.
	 */
	@NonNull
	@Override
	public byte[] signData(@NonNull byte[] data, @NonNull HashAlgorithm hashAlgorithm) {
		try {
			final Signature rsa = Signature.getInstance(getSignatureAlgorithm(hashAlgorithm));
			rsa.initSign(signingKey.getPrivateKey());
			rsa.update(data);
			return rsa.sign();
		} catch (Exception e) {
			...
		}
	}

	@NonNull
	@Override
	public EncryptionAlgorithm getEncryptionAlgorithm() {
		return EncryptionAlgorithm.RSA;
	}
}

Editing a Digitally Signed Document

When displaying digitally signed documents, PSPDFKit will allow annotation editing unless a DocMDP transform method is specified under the TransformMethod key of the signature information dictionary. When PSPDFKit is used for the signing process, this method is never set, which means annotation editing remains enabled.

Removing a Digital Signature

If you want to remove a signature again, you just need to access the signed SignatureFormField and call removeSignature() or removeSignatureAsync(). This will remove the DigitalSignatureInfo from the given SignatureFormField.