Adding a Digital Signature to a PDF on 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 aKeyStore.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 availableEncryptionAlgorithm
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 PDFdata
using the requestedHashAlgorithm
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
.