Browse Source

PDFTool(Android) - 1.SDK 更新 2.kotlin 版本数字签名示例

liuxiaolong 1 year ago
parent
commit
0dc12b0fe1

BIN
ComPDFKit_Repo/compdfkit/ComPDFKit.aar


+ 1 - 0
Samples/src/main/java/com/compdfkit/samples/samples/AnnotationTest.java

@@ -135,6 +135,7 @@ public class AnnotationTest extends PDFSamples {
         CPDFTextAttribute textAttribute = new CPDFTextAttribute(CPDFTextAttribute.FontNameHelper.obtainFontName(
                 CPDFTextAttribute.FontNameHelper.FontType.Courier, false, false
         ), 12, Color.RED);
+
         freetextAnnotation.setFreetextDa(textAttribute);
         // set text color opacity
         freetextAnnotation.setAlpha(255);

+ 1 - 4
Samples/src/main/res/values/strings.xml

@@ -62,11 +62,8 @@
     <string name="annotation_import_export_test_title">AnnotationImportExport</string>
     <string name="annotation_import_export_test_desc">This sample shows how to set up the export and import of annotations. The document from which the annotations are exported is an xfdf file</string>
 
-    <string name="annotation_content_edit_title">TextEditTest</string>
-    <string name="annotation_content_edit_desc">PDF Document Text Edit(insert,delete,replace)</string>
-
     <string name="digital_signature_title">DigitalSignature</string>
-    <string name="digital_signature_desc">DigitalSignature Description</string>
+    <string name="digital_signature_desc">This sample demonstrates the creation of digital certificates, the generation of digital signatures, the verification of digital certificates, the validation of digital signatures, the reading of digital signature information, certificate trust, and signature removal functionality.</string>
 
     <string name="tools_allowed">Allowed</string>
     <string name="tools_not_allowed">Not Allowed</string>

BIN
Samples_kotlin/src/main/assets/Certificate.pfx


BIN
Samples_kotlin/src/main/assets/CommonFivePage_Signed.pdf


BIN
Samples_kotlin/src/main/assets/Signed.pdf


+ 2 - 0
Samples_kotlin/src/main/java/com/compdfkit/samples/SampleApplication.kt

@@ -14,6 +14,7 @@ import com.compdfkit.samples.samples.AnnotationTest
 import com.compdfkit.samples.samples.BackgroundTest
 import com.compdfkit.samples.samples.BatesTest
 import com.compdfkit.samples.samples.BookmarkTest
+import com.compdfkit.samples.samples.DigitalSignaturesTest
 import com.compdfkit.samples.samples.DocumentInfoTest
 import com.compdfkit.samples.samples.EncryptTest
 import com.compdfkit.samples.samples.FlattenTest
@@ -38,6 +39,7 @@ class SampleApplication : Application() {
         super.onCreate()
         instance = this
         samplesList.clear()
+        samplesList.add(DigitalSignaturesTest())
         samplesList.add(BookmarkTest())
         samplesList.add(OutlineTest())
         samplesList.add(PDFToImageTest())

+ 290 - 0
Samples_kotlin/src/main/java/com/compdfkit/samples/samples/DigitalSignaturesTest.kt

@@ -0,0 +1,290 @@
+/**
+ * Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
+ *
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+package com.compdfkit.samples.samples
+
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.graphics.RectF
+import com.compdfkit.core.annotation.form.CPDFSignatureWidget
+import com.compdfkit.core.annotation.form.CPDFWidget
+import com.compdfkit.core.document.CPDFDocument
+import com.compdfkit.core.signature.CPDFDigitalSigConfig
+import com.compdfkit.core.signature.CPDFOwnerInfo
+import com.compdfkit.core.signature.CPDFSignature
+import com.compdfkit.core.signature.CPDFSignature.CertUsage
+import com.compdfkit.samples.PDFSamples
+import com.compdfkit.samples.R
+import com.compdfkit.samples.util.DateUtil
+import com.compdfkit.samples.util.DateUtil.transformPDFDate
+import com.compdfkit.samples.util.FileUtils.getAssetsTempFile
+import com.compdfkit.samples.util.FileUtils.getNameWithoutExtension
+import com.compdfkit.samples.util.OutputListener
+import java.io.File
+
+class DigitalSignaturesTest : PDFSamples() {
+
+    init {
+        setTitle(R.string.digital_signature_title)
+        setDescription(R.string.digital_signature_desc)
+    }
+
+    override fun run(outputListener: OutputListener?) {
+        super.run(outputListener)
+        printHead()
+        printDividingLine()
+
+        //---------
+        //Samples 0: Create a pfx format certificate for digital signature use
+        generateCertificate()
+
+        //--------
+        //Samples 1: Create form fields for digital signature and digital signature using created pfx format certificate
+        createSignature()
+
+        //--------
+        //Samples 2: Verify signature
+        verifySignatureInfo()
+
+        //--------
+        //Samples 3: Verify certificate
+        verifyCertificate()
+
+        //--------
+        //Samples 4: Print digital signature info
+        printDigitalSignatureInfo()
+
+        //--------
+        //Samples 5: Trust certificate
+        trustCertificate()
+
+        //--------
+        //Samples 6:Remove digital signature from PDF document
+        removeDigitalSignature()
+        printFooter()
+    }
+
+    /**
+     * **Create pfx format certificate for digital signature use** <br></br>
+     * <br></br><br></br>
+     * **Password:** ComPDFKit <br></br>
+     * **C=SG:** This represents the country code "SG," which typically stands for Singapore.<br></br><br></br>
+     * **O=ComPDFKit:** This is the Organization (O) field, indicating the name of the organization or entity,
+     * in this case, "ComPDFKit." <br></br><br></br>
+     * **D=R&D Department:** This is the Department (D) field,
+     * indicating the specific department within the organization,
+     * in this case, "R&D Department."<br></br><br></br>
+     * **CN=Alan:** This is the Common Name (CN) field, which usually represents the name
+     * of the individual or entity. In this case, it is "Alan."<br></br><br></br>
+     * **emailAddress=xxxx@example.com:** Email is xxxx@example.com <br></br><br></br>
+     * **CPDFSignature.CertUsage.PDFAll: **Used for both digital signing and data validation simultaneously.<br></br><br></br>
+     * **is_2048: ** Enhanced security encryption.<br></br><br></br>
+     */
+    private fun generateCertificate() {
+        outputListener?.println("generate certificate")
+        val password = "ComPDFKit"
+        val ownerInfo = CPDFOwnerInfo().apply {
+            commonName = "Alan"
+            orgnize = "ComPDFKit"
+            email = "xxxx@example.com"
+            country = "SG"
+        }
+        val flag = CertUsage.PDFAll
+        val certFile = File(outputDir(), "certificate/Certificate.pfx")
+        certFile.parentFile?.mkdirs()
+        val result = CPDFSignature.generatePKCS12Cert(ownerInfo, password, certFile.absolutePath, flag, true)
+        if (result) {
+            outputListener?.println("Done. File saved in Certificate.pfx")
+            outputListener?.println("Generate PKCS12 certificate done")
+        }
+        addFileList(certFile.absolutePath)
+        printDividingLine()
+    }
+
+    private fun createSignature() {
+        outputListener?.println("Create digital signature.")
+        val document = CPDFDocument(context())
+        document.open(getAssetsTempFile(context(), "CommonFivePage.pdf"))
+        //Insert a Form Signature Widget (unsigned)
+        val cpdfPage = document.pageAtIndex(0)
+        val pageSize = cpdfPage.size
+        val signatureWidget = cpdfPage.addFormWidget(CPDFWidget.WidgetType.Widget_SignatureFields) as CPDFSignatureWidget
+        signatureWidget.fieldName = "Signature1"
+        signatureWidget.fillColor = Color.parseColor("#FF96B4D2")
+        signatureWidget.rect = kotlin.run {
+            cpdfPage.convertRectToPage(false, pageSize.width(), pageSize.height(), RectF(28f, 420f, 150f, 370f))
+        }
+        signatureWidget.updateAp()
+
+
+        // Make a digital signature
+        val fileName = getNameWithoutExtension(document.fileName) + "_Signed.pdf"
+        val file = File(outputDir(), "digitalSignature/$fileName")
+        file.parentFile?.mkdirs()
+        val password = "ComPDFKit"
+        val certPath = getAssetsTempFile(context(), "Certificate.pfx")
+        val cpdfx509 = CPDFSignature.getX509ByPKCS12Cert(certPath, password)
+        val location = cpdfx509.certInfo.subject.country
+        val reason = "I am the owner of the document."
+        val bitmap = BitmapFactory.decodeFile(getAssetsTempFile(context(), "ComPDFKit.png"))
+        // Describe signature appearance information
+        val sigConfig = CPDFDigitalSigConfig().apply {
+            text = cpdfx509.certInfo.subject.commonName
+            textColor = Color.BLACK
+            contentColor = Color.BLACK
+            logo = bitmap
+            val builder = StringBuilder()
+            builder.append("Name: ").append(cpdfx509.certInfo.subject.commonName).append("\n")
+                    .append("Date: ").append(DateUtil.getDataTime("yyyy.MM.dd HH:mm:ss")).append("\n")
+                    .append("Reason: ").append(reason).append("\n")
+                    .append("Location: ").append(location).append("\n")
+                    .append("DN: ").append(cpdfx509.certInfo.subject)
+            content = builder.toString()
+            isContentAlginLeft = false
+            isDrawLogo = true
+        }
+
+        val updateSignAp = signatureWidget.updateApWithDigitalSigConfig(sigConfig)
+        if (updateSignAp) {
+            val writeSignResult = document.writeSignature(signatureWidget,
+                    file.absolutePath,
+                    certPath,
+                    password,
+                    location,
+                    reason,
+                    CPDFDocument.PDFDocMdpP.PDFDocMdpPForbidAllModify
+            )
+            if (writeSignResult) {
+                addFileList(file.absolutePath)
+                outputListener?.println("Done. File saved in $fileName")
+                outputListener?.println("Create digital signature done")
+            }
+        }
+        printDividingLine()
+    }
+
+    private fun verifySignatureInfo() {
+        outputListener?.println("Verify digital signature")
+        val document = CPDFDocument(context())
+        document.open(getAssetsTempFile(context(), "Signed.pdf"))
+        // Iterate through all digital signatures
+        for (i in 0 until document.signatureCount) {
+            val signature = document.getPdfSignature(i)
+            // Check if the signer array exists and is not empty
+            if (signature.signerArr != null && signature.signerArr.isNotEmpty()) {
+                val signer = signature.signerArr[0]
+
+                // Verify the validity of the signature
+                val verifyValid = signature.verify(document)
+
+                // Verify if the document has not been modified
+                val unmodified = signature.verifyDocument(document)
+
+                // Determine if the signature is valid and the document is unmodified
+                val isSignVerified = verifyValid && unmodified
+
+                // Check if the certificate is trusted
+                val certChainTrusted = signer.cert.verifyGetChain(document.context, signature)
+                val certificateIsTrusted = signer.cert.checkCertificateIsTrusted(document.context)
+                val certIsTrusted = certChainTrusted || certificateIsTrusted
+
+                // Check if the certificate has expired
+                val isExpired = signer.cert.isExpired
+
+                // Take appropriate actions based on the verification results
+                if (isSignVerified && certIsTrusted) {
+                    // Signature is valid and the certificate is trusted
+                    // Perform corresponding actions
+                } else if (isSignVerified && !certIsTrusted) {
+                    // Signature is valid but the certificate is not trusted
+                    // Perform corresponding actions
+                } else {
+                    // Signature is invalid
+                    // Perform corresponding actions
+                }
+                outputListener?.println("Is the certificate trusted: $certIsTrusted")
+                outputListener?.println("Is the signature verified: $isSignVerified")
+            }
+        }
+        outputListener?.println("Verify digital signature done.")
+        printDividingLine()
+    }
+
+    private fun verifyCertificate() {
+        outputListener?.println("verify certificate")
+        // Verify whether the specified certificate file is trusted
+        val certFilePath = getAssetsTempFile(context(), "Certificate.pfx")
+        val password = "ComPDFKit"
+        if (CPDFSignature.checkPKCS12Password(certFilePath, password)) {
+            val x509 = CPDFSignature.getX509ByPKCS12Cert(certFilePath, password)
+            val result = x509.addToTrustedCertificates(context())
+            val isTrusted = x509.checkCertificateIsTrusted(context())
+            if (isTrusted) {
+                outputListener?.println("Certificate is trusted")
+            } else {
+                outputListener?.println("Certificate is not trusted")
+            }
+            outputListener?.println("Verify certificate done.")
+        }
+        printDividingLine()
+    }
+
+    private fun printDigitalSignatureInfo() {
+        outputListener?.println("Print digital signature info.")
+        val document = CPDFDocument(context())
+        document.open(getAssetsTempFile(context(), "Signed.pdf"))
+        for (i in 0 until document.signatureCount) {
+            val signature = document.getPdfSignature(i)
+            // Check if the signer array exists and is not empty
+            if (signature.signerArr != null && signature.signerArr.isNotEmpty()) {
+                val signer = signature.signerArr[0]
+                val subject = signer.cert.certInfo.subject
+                outputListener?.println("Name: ${signature.name}")
+                outputListener?.println("Location: ${signature.location}")
+                outputListener?.println("Reason: ${signature.reason}")
+                outputListener?.println("Date: ${transformPDFDate(signature.date)}")
+                outputListener?.println("Subject: $subject")
+            }
+        }
+        outputListener?.println("Print digital signature info done.")
+        printDividingLine()
+    }
+
+    private fun trustCertificate() {
+        outputListener?.println("Trust certificate")
+        val document = CPDFDocument(context())
+        document.open(getAssetsTempFile(context(), "Signed.pdf"))
+        val signature = document.getPdfSignature(0)
+        val signer = signature.signerArr[0]
+        val cpdfx509 = signer.cert
+        outputListener?.println("Certificate trusted status: ${cpdfx509.checkCertificateIsTrusted(context())}")
+        outputListener?.println("---Begin trusted---")
+        cpdfx509.addToTrustedCertificates(context())
+        outputListener?.println("Certificate trusted status: ${cpdfx509.checkCertificateIsTrusted(context())}")
+        outputListener?.println("Trust certificate done.")
+        printDividingLine()
+    }
+
+    private fun removeDigitalSignature() {
+        outputListener?.println("Remove digital signature")
+        val document = CPDFDocument(context())
+        document.open(getAssetsTempFile(context(), "Signed.pdf"))
+        for (i in 0 until document.signatureCount) {
+            val signature = document.getPdfSignature(i)
+            if (i == 0) {
+                document.removeSignature(signature, true, null)
+            }
+        }
+        val fileName = getNameWithoutExtension(document.fileName) + "_RemoveSign.pdf"
+        val file = File(outputDir(), "digitalSignature/$fileName")
+        saveSamplePDF(document, file, true)
+        outputListener?.println("Done. File saved in $fileName")
+        printDividingLine()
+    }
+}

+ 7 - 0
Samples_kotlin/src/main/java/com/compdfkit/samples/util/DateUtil.kt

@@ -9,6 +9,8 @@
 package com.compdfkit.samples.util
 
 import android.text.TextUtils
+import java.text.SimpleDateFormat
+import java.util.Date
 
 object DateUtil {
 
@@ -28,4 +30,9 @@ object DateUtil {
             inputDate
         }
     }
+
+    fun getDataTime(format: String?): String? {
+        val df = SimpleDateFormat(format)
+        return df.format(Date())
+    }
 }

+ 4 - 1
Samples_kotlin/src/main/res/values/strings.xml

@@ -1,6 +1,6 @@
 <resources>
     <string name="app_name">Samples_ComPDFKit</string>
-    <string name="samples">Samples</string>
+    <string name="samples">Samples Kotlin</string>
 
     <string name="sample_header">Running %s sample&#8230;</string>
     <string name="sample_footer">Done!</string>
@@ -62,6 +62,9 @@
     <string name="annotation_import_export_test_title">AnnotationImportExport</string>
     <string name="annotation_import_export_test_desc">This sample shows how to set up the export and import of annotations. The document from which the annotations are exported is an xfdf file</string>
 
+    <string name="digital_signature_title">DigitalSignature</string>
+    <string name="digital_signature_desc">This sample demonstrates the creation of digital certificates, the generation of digital signatures, the verification of digital certificates, the validation of digital signatures, the reading of digital signature information, certificate trust, and signature removal functionality.</string>
+
     <string name="tools_allowed">Allowed</string>
     <string name="tools_not_allowed">Not Allowed</string>