使用 iText7 和 Vb.Net 签署 Pdf 时出现 MissingMethodException
MissingMethodException when signing a Pdf with iText7 and Vb.Net
我正在尝试测试翻译成 Vb.Net 的 iText 文档示例,但是在执行 pdfSigner.SignDetached(...) 时我遇到了下一个奇怪的异常
MissingMethodException:'System.Collections.IEnumerator
Org.BouncyCastle.Asn1.Asn1Sequence.GetObjects()'
代码成功读取 pfx 证书和源文件,并创建目标文件但在最后一步失败导致目标文件损坏:
Imports System.IO
Imports Org.BouncyCastle.Crypto
Imports Org.BouncyCastle.X509
Imports iText.Kernel.Geom
Imports iText.Kernel.Pdf
Imports iText.Signatures
Imports Org.BouncyCastle.Pkcs
Public Class SignHelloWorld
Public Shared ReadOnly root As String = Environment.GetFolderPath(Environment.SpecialFolder.Personal) & "\tmp\itext7\"
Public Shared ReadOnly DEST As String = root & "results\signatures\chapter01\"
Public Shared ReadOnly KEYSTORE As String = root & "resources\encryption\myCert.pfx"
Public Shared ReadOnly SRC As String = root & "resources\pdfs\hello.pdf"
Public Shared ReadOnly PASSWORD As Char() = "1234".ToCharArray()
Public Shared ReadOnly RESULT_FILES As String() = {"hello_signed1.pdf", "hello_signed2.pdf", "hello_signed3.pdf", "hello_signed4.pdf"}
Public Sub Sign(ByVal src As String, ByVal dest As String, ByVal chain As X509Certificate(), ByVal pk As ICipherParameters, ByVal digestAlgorithm As String, ByVal subfilter As PdfSigner.CryptoStandard, ByVal reason As String, ByVal location As String)
Dim reader As PdfReader = New PdfReader(src)
Dim signer As PdfSigner = New PdfSigner(reader, New FileStream(dest, FileMode.Create), New StampingProperties())
Dim rect As Rectangle = New Rectangle(36, 648, 200, 100)
Dim appearance As PdfSignatureAppearance = signer.GetSignatureAppearance()
appearance.SetReason(reason).SetLocation(location).SetReuseAppearance(False).SetPageRect(rect).SetPageNumber(1)
signer.SetFieldName("sig")
Dim pks As IExternalSignature = New PrivateKeySignature(pk, digestAlgorithm)
signer.SignDetached(pks, chain, Nothing, Nothing, Nothing, 0, subfilter)
reader.Close()
End Sub
Public Shared Sub Main(ByVal args As String())
Dim directory As DirectoryInfo = New DirectoryInfo(DEST)
directory.Create()
Dim pk12 As Pkcs12Store = New Pkcs12Store(New FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD)
Dim [alias] As String = Nothing
For Each a In pk12.Aliases
[alias] = (CStr(a))
If pk12.IsKeyEntry([alias]) Then Exit For
Next
Dim pk As ICipherParameters = pk12.GetKey([alias]).Key
Dim ce As X509CertificateEntry() = pk12.GetCertificateChain([alias])
Dim chain As X509Certificate() = New X509Certificate(ce.Length - 1) {}
For k As Integer = 0 To ce.Length - 1
chain(k) = ce(k).Certificate
Next
Dim app As SignHelloWorld = New SignHelloWorld()
app.Sign(SRC, DEST & RESULT_FILES(0), chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent")
app.Sign(SRC, DEST & RESULT_FILES(1), chain, pk, DigestAlgorithms.SHA512, PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent")
app.Sign(SRC, DEST & RESULT_FILES(2), chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent")
app.Sign(SRC, DEST & RESULT_FILES(3), chain, pk, DigestAlgorithms.RIPEMD160, PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent")
End Sub
End Class
据我所知,当前的 iText 7 开发版本 (7.1.11-SNAPSHOT) 是针对 BouncyCastle 1.8.5 编译的,事实上,在 BC 1.8.5 中,您可以在 Asn1Sequence.cs
[Obsolete("Use GetEnumerator() instead")]
public IEnumerator GetObjects()
{
return GetEnumerator();
}
但在 BC 1.8.6 中,该方法已从 Asn1Sequence.cs
中删除。
因此,在使用 iText 7 v7.1.10 或更早版本进行开发时,请目前仍使用 BouncyCastle 1.8.5。
顺便说一句,BouncyCastle 以在发布中引入 API 重大更改而闻名,只有微版本更改。大多数其他项目只会在发布时删除方法(即使标记为过时),如果不是在主要版本中,至少在次要版本中有更改。
因此,在使用 BC 时,您必须始终非常注意要使用的确切版本。
我正在尝试测试翻译成 Vb.Net 的 iText 文档示例,但是在执行 pdfSigner.SignDetached(...) 时我遇到了下一个奇怪的异常
MissingMethodException:'System.Collections.IEnumerator Org.BouncyCastle.Asn1.Asn1Sequence.GetObjects()'
代码成功读取 pfx 证书和源文件,并创建目标文件但在最后一步失败导致目标文件损坏:
Imports System.IO
Imports Org.BouncyCastle.Crypto
Imports Org.BouncyCastle.X509
Imports iText.Kernel.Geom
Imports iText.Kernel.Pdf
Imports iText.Signatures
Imports Org.BouncyCastle.Pkcs
Public Class SignHelloWorld
Public Shared ReadOnly root As String = Environment.GetFolderPath(Environment.SpecialFolder.Personal) & "\tmp\itext7\"
Public Shared ReadOnly DEST As String = root & "results\signatures\chapter01\"
Public Shared ReadOnly KEYSTORE As String = root & "resources\encryption\myCert.pfx"
Public Shared ReadOnly SRC As String = root & "resources\pdfs\hello.pdf"
Public Shared ReadOnly PASSWORD As Char() = "1234".ToCharArray()
Public Shared ReadOnly RESULT_FILES As String() = {"hello_signed1.pdf", "hello_signed2.pdf", "hello_signed3.pdf", "hello_signed4.pdf"}
Public Sub Sign(ByVal src As String, ByVal dest As String, ByVal chain As X509Certificate(), ByVal pk As ICipherParameters, ByVal digestAlgorithm As String, ByVal subfilter As PdfSigner.CryptoStandard, ByVal reason As String, ByVal location As String)
Dim reader As PdfReader = New PdfReader(src)
Dim signer As PdfSigner = New PdfSigner(reader, New FileStream(dest, FileMode.Create), New StampingProperties())
Dim rect As Rectangle = New Rectangle(36, 648, 200, 100)
Dim appearance As PdfSignatureAppearance = signer.GetSignatureAppearance()
appearance.SetReason(reason).SetLocation(location).SetReuseAppearance(False).SetPageRect(rect).SetPageNumber(1)
signer.SetFieldName("sig")
Dim pks As IExternalSignature = New PrivateKeySignature(pk, digestAlgorithm)
signer.SignDetached(pks, chain, Nothing, Nothing, Nothing, 0, subfilter)
reader.Close()
End Sub
Public Shared Sub Main(ByVal args As String())
Dim directory As DirectoryInfo = New DirectoryInfo(DEST)
directory.Create()
Dim pk12 As Pkcs12Store = New Pkcs12Store(New FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD)
Dim [alias] As String = Nothing
For Each a In pk12.Aliases
[alias] = (CStr(a))
If pk12.IsKeyEntry([alias]) Then Exit For
Next
Dim pk As ICipherParameters = pk12.GetKey([alias]).Key
Dim ce As X509CertificateEntry() = pk12.GetCertificateChain([alias])
Dim chain As X509Certificate() = New X509Certificate(ce.Length - 1) {}
For k As Integer = 0 To ce.Length - 1
chain(k) = ce(k).Certificate
Next
Dim app As SignHelloWorld = New SignHelloWorld()
app.Sign(SRC, DEST & RESULT_FILES(0), chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent")
app.Sign(SRC, DEST & RESULT_FILES(1), chain, pk, DigestAlgorithms.SHA512, PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent")
app.Sign(SRC, DEST & RESULT_FILES(2), chain, pk, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent")
app.Sign(SRC, DEST & RESULT_FILES(3), chain, pk, DigestAlgorithms.RIPEMD160, PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent")
End Sub
End Class
据我所知,当前的 iText 7 开发版本 (7.1.11-SNAPSHOT) 是针对 BouncyCastle 1.8.5 编译的,事实上,在 BC 1.8.5 中,您可以在 Asn1Sequence.cs
[Obsolete("Use GetEnumerator() instead")]
public IEnumerator GetObjects()
{
return GetEnumerator();
}
但在 BC 1.8.6 中,该方法已从 Asn1Sequence.cs
中删除。
因此,在使用 iText 7 v7.1.10 或更早版本进行开发时,请目前仍使用 BouncyCastle 1.8.5。
顺便说一句,BouncyCastle 以在发布中引入 API 重大更改而闻名,只有微版本更改。大多数其他项目只会在发布时删除方法(即使标记为过时),如果不是在主要版本中,至少在次要版本中有更改。
因此,在使用 BC 时,您必须始终非常注意要使用的确切版本。