使用 pdfbox 2.x.x 使用 bouncycastle 进行 PDF 签名
Pdf signing with bouncycastle using pdfbox 2.x.x
我试图在 bouncycastle 中找到使用 pdfbox 版本 2.x.x 签署 pdf 的示例,我看到的只是 pdfbox 版本 1.8.9
这适用于 pdfbox 1.8.9 但不适用于 API 已更改的 2.x.x 版本。找不到特定于同一用例的文档,但在 2.x.x 版本的 pdfbox 中。
有没有人可以帮忙。
示例在源代码下载或在线此处:
https://svn.apache.org/viewvc/pdfbox/branches/2.0/examples/src/main/java/org/apache/pdfbox/examples/signature/
下面是当前的 CreateSignature 示例。但是,您需要上述目录中的其他文件。添加新功能时,文件结构可能会不时更改;所以下面的代码更像是一种快照。最好的方法是从上面的 link 或发布版本中检索当前代码。
public class CreateSignature extends CreateSignatureBase
{
/**
* Initialize the signature creator with a keystore and certficate password.
*
* @param keystore the pkcs12 keystore containing the signing certificate
* @param pin the password for recovering the key
* @throws KeyStoreException if the keystore has not been initialized (loaded)
* @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found
* @throws UnrecoverableKeyException if the given password is wrong
* @throws CertificateException if the certificate is not valid as signing time
* @throws IOException if no certificate could be found
*/
public CreateSignature(KeyStore keystore, char[] pin)
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException, IOException
{
super(keystore, pin);
}
/**
* Signs the given PDF file. Alters the original file on disk.
* @param file the PDF file to sign
* @throws IOException if the file could not be read or written
*/
public void signDetached(File file) throws IOException
{
signDetached(file, file, null);
}
/**
* Signs the given PDF file.
* @param inFile input PDF file
* @param outFile output PDF file
* @throws IOException if the input file could not be read
*/
public void signDetached(File inFile, File outFile) throws IOException
{
signDetached(inFile, outFile, null);
}
/**
* Signs the given PDF file.
* @param inFile input PDF file
* @param outFile output PDF file
* @param tsaClient optional TSA client
* @throws IOException if the input file could not be read
*/
public void signDetached(File inFile, File outFile, TSAClient tsaClient) throws IOException
{
if (inFile == null || !inFile.exists())
{
throw new FileNotFoundException("Document for signing does not exist");
}
FileOutputStream fos = new FileOutputStream(outFile);
// sign
PDDocument doc = PDDocument.load(inFile);
signDetached(doc, fos, tsaClient);
doc.close();
}
public void signDetached(PDDocument document, OutputStream output, TSAClient tsaClient)
throws IOException
{
setTsaClient(tsaClient);
int accessPermissions = SigUtils.getMDPPermission(document);
if (accessPermissions == 1)
{
throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
}
// create signature dictionary
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("Example User");
signature.setLocation("Los Angeles, CA");
signature.setReason("Testing");
// TODO extract the above details from the signing certificate? Reason as a parameter?
// the signing date, needed for valid signature
signature.setSignDate(Calendar.getInstance());
// Optional: certify
if (accessPermissions == 0)
{
SigUtils.setMDPPermission(document, signature, 2);
}
if (isExternalSigning())
{
System.out.println("Sign externally...");
document.addSignature(signature);
ExternalSigningSupport externalSigning =
document.saveIncrementalForExternalSigning(output);
// invoke external signature service
byte[] cmsSignature = sign(externalSigning.getContent());
// set signature bytes received from the service
externalSigning.setSignature(cmsSignature);
}
else
{
// register signature dictionary and sign interface
document.addSignature(signature, this);
// write incremental (only for signing purpose)
document.saveIncremental(output);
}
}
public static void main(String[] args) throws IOException, GeneralSecurityException
{
if (args.length < 3)
{
usage();
System.exit(1);
}
String tsaUrl = null;
boolean externalSig = false;
for (int i = 0; i < args.length; i++)
{
if (args[i].equals("-tsa"))
{
i++;
if (i >= args.length)
{
usage();
System.exit(1);
}
tsaUrl = args[i];
}
if (args[i].equals("-e"))
{
externalSig = true;
}
}
// load the keystore
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] password = args[1].toCharArray(); // TODO use Java 6 java.io.Console.readPassword
keystore.load(new FileInputStream(args[0]), password);
// TODO alias command line argument
// TSA client
TSAClient tsaClient = null;
if (tsaUrl != null)
{
MessageDigest digest = MessageDigest.getInstance("SHA-256");
tsaClient = new TSAClient(new URL(tsaUrl), null, null, digest);
}
// sign PDF
CreateSignature signing = new CreateSignature(keystore, password);
signing.setExternalSigning(externalSig);
File inFile = new File(args[2]);
String name = inFile.getName();
String substring = name.substring(0, name.lastIndexOf('.'));
File outFile = new File(inFile.getParent(), substring + "_signed.pdf");
signing.signDetached(inFile, outFile, tsaClient);
}
private static void usage()
{
System.err.println("usage: java " + CreateSignature.class.getName() + " " +
"<pkcs12_keystore> <password> <pdf_to_sign>\n" + "" +
"options:\n" +
" -tsa <url> sign timestamp using the given TSA server\n" +
" -e sign using external signature creation scenario");
}
}
我试图在 bouncycastle 中找到使用 pdfbox 版本 2.x.x 签署 pdf 的示例,我看到的只是 pdfbox 版本 1.8.9
这适用于 pdfbox 1.8.9 但不适用于 API 已更改的 2.x.x 版本。找不到特定于同一用例的文档,但在 2.x.x 版本的 pdfbox 中。
有没有人可以帮忙。
示例在源代码下载或在线此处: https://svn.apache.org/viewvc/pdfbox/branches/2.0/examples/src/main/java/org/apache/pdfbox/examples/signature/
下面是当前的 CreateSignature 示例。但是,您需要上述目录中的其他文件。添加新功能时,文件结构可能会不时更改;所以下面的代码更像是一种快照。最好的方法是从上面的 link 或发布版本中检索当前代码。
public class CreateSignature extends CreateSignatureBase
{
/**
* Initialize the signature creator with a keystore and certficate password.
*
* @param keystore the pkcs12 keystore containing the signing certificate
* @param pin the password for recovering the key
* @throws KeyStoreException if the keystore has not been initialized (loaded)
* @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found
* @throws UnrecoverableKeyException if the given password is wrong
* @throws CertificateException if the certificate is not valid as signing time
* @throws IOException if no certificate could be found
*/
public CreateSignature(KeyStore keystore, char[] pin)
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException, IOException
{
super(keystore, pin);
}
/**
* Signs the given PDF file. Alters the original file on disk.
* @param file the PDF file to sign
* @throws IOException if the file could not be read or written
*/
public void signDetached(File file) throws IOException
{
signDetached(file, file, null);
}
/**
* Signs the given PDF file.
* @param inFile input PDF file
* @param outFile output PDF file
* @throws IOException if the input file could not be read
*/
public void signDetached(File inFile, File outFile) throws IOException
{
signDetached(inFile, outFile, null);
}
/**
* Signs the given PDF file.
* @param inFile input PDF file
* @param outFile output PDF file
* @param tsaClient optional TSA client
* @throws IOException if the input file could not be read
*/
public void signDetached(File inFile, File outFile, TSAClient tsaClient) throws IOException
{
if (inFile == null || !inFile.exists())
{
throw new FileNotFoundException("Document for signing does not exist");
}
FileOutputStream fos = new FileOutputStream(outFile);
// sign
PDDocument doc = PDDocument.load(inFile);
signDetached(doc, fos, tsaClient);
doc.close();
}
public void signDetached(PDDocument document, OutputStream output, TSAClient tsaClient)
throws IOException
{
setTsaClient(tsaClient);
int accessPermissions = SigUtils.getMDPPermission(document);
if (accessPermissions == 1)
{
throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
}
// create signature dictionary
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("Example User");
signature.setLocation("Los Angeles, CA");
signature.setReason("Testing");
// TODO extract the above details from the signing certificate? Reason as a parameter?
// the signing date, needed for valid signature
signature.setSignDate(Calendar.getInstance());
// Optional: certify
if (accessPermissions == 0)
{
SigUtils.setMDPPermission(document, signature, 2);
}
if (isExternalSigning())
{
System.out.println("Sign externally...");
document.addSignature(signature);
ExternalSigningSupport externalSigning =
document.saveIncrementalForExternalSigning(output);
// invoke external signature service
byte[] cmsSignature = sign(externalSigning.getContent());
// set signature bytes received from the service
externalSigning.setSignature(cmsSignature);
}
else
{
// register signature dictionary and sign interface
document.addSignature(signature, this);
// write incremental (only for signing purpose)
document.saveIncremental(output);
}
}
public static void main(String[] args) throws IOException, GeneralSecurityException
{
if (args.length < 3)
{
usage();
System.exit(1);
}
String tsaUrl = null;
boolean externalSig = false;
for (int i = 0; i < args.length; i++)
{
if (args[i].equals("-tsa"))
{
i++;
if (i >= args.length)
{
usage();
System.exit(1);
}
tsaUrl = args[i];
}
if (args[i].equals("-e"))
{
externalSig = true;
}
}
// load the keystore
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] password = args[1].toCharArray(); // TODO use Java 6 java.io.Console.readPassword
keystore.load(new FileInputStream(args[0]), password);
// TODO alias command line argument
// TSA client
TSAClient tsaClient = null;
if (tsaUrl != null)
{
MessageDigest digest = MessageDigest.getInstance("SHA-256");
tsaClient = new TSAClient(new URL(tsaUrl), null, null, digest);
}
// sign PDF
CreateSignature signing = new CreateSignature(keystore, password);
signing.setExternalSigning(externalSig);
File inFile = new File(args[2]);
String name = inFile.getName();
String substring = name.substring(0, name.lastIndexOf('.'));
File outFile = new File(inFile.getParent(), substring + "_signed.pdf");
signing.signDetached(inFile, outFile, tsaClient);
}
private static void usage()
{
System.err.println("usage: java " + CreateSignature.class.getName() + " " +
"<pkcs12_keystore> <password> <pdf_to_sign>\n" + "" +
"options:\n" +
" -tsa <url> sign timestamp using the given TSA server\n" +
" -e sign using external signature creation scenario");
}
}