插入多个(2次)数字签名,我发现pdf里面有3个信息字典
Insert multiple(2 times)digital signatures,i found there are 3 info-dictionary in the pdf
我遇到了同样的问题(在 C++ 中使用 podofo 开发)。 Insert multiple(2 times)数字签名后,发现pdf文件中有3个信息——字典:
如何在不使前一个签名失效的情况下添加两个数字签名?
谢谢!
我用记事本++打开文件,发现不一样
the first: 97 0 obj<</Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0) /Author(edison qian) /Keywords(GISerClub) /Creator(? M i c r o s o f t ? W o r d 2 0 1 3)
/CreationDate(D:20150601200942+08'00') /ModDate(D:20150601200942+08'00') /Producer(? M i c r o s o f t ? W o r d 2 0 1 3) >>
the second: 97 0 obj<</Author(edison qian)/CreationDate(D:20150601200942+08'00')/Creator(? M i c r o s o f t ? W o r d 2 0 1 3)/Keywords(GISerClub)
/ModDate(D:20190426155330+08'00')/Producer(? M i c r o s o f t ? W o r d 2 0 1 3)/Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0)>>
the third: 97 0 obj<</Author(edison qian)/CreationDate(D:20150601200942+08'00')/Creator(? M i c r o s o f t ? W o r d 2 0 1 3)/Keywords(GISerClub)
/ModDate(D:20190426155428+08'00')/Producer(? M i c r o s o f t ? W o r d 2 0 1 3)/Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0)>>
我的代码:
bool pdfSign(PdfMemDocument* document,PdfOutputDevice* outputDevice,PKCS12* p12,RSA* rsa,int npage,PdfRect rect,int min_signature_size,const char* ImgFile/*,PdfDate& sigData*/)
{
PdfInfo* pInfo = document->GetInfo();
TKeyMap itm = pInfo->GetObject()->GetDictionary().GetKeys();
PdfObject* pobj = pInfo->GetObject()->GetDictionary().GetKey(PdfName("ModDate"));
PdfString modDate = pobj->GetString();
string sDate = modDate.GetString();
string sutf8Date = modDate.GetStringUtf8();
PdfOutlines* pOutLine = document->GetOutlines();
TKeyMap itm2 = pOutLine->GetObject()->GetDictionary().GetKeys();
const char *field_name = NULL;
bool field_use_existing = false;
int annot_page = npage;
//double annot_left = 80.0, annot_top = 70.0, annot_width = 150.0, annot_height = 150.0;
bool annot_print = true;
const char *reason = "I agree";
int result = 0;
PdfSignatureField *pSignField = NULL;
try
{
PdfSignOutputDevice signer( outputDevice );
PdfAcroForm* pAcroForm = document->GetAcroForm();
if( !pAcroForm )
PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "acroForm == NULL" );
if( !pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) ||
!pAcroForm->GetObject()->GetDictionary().GetKey( PdfName( "SigFlags" ) )->IsNumber() ||
pAcroForm->GetObject()->GetDictionary().GetKeyAsLong( PdfName( "SigFlags" ) ) != 3 )
{
if( pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) )
pAcroForm->GetObject()->GetDictionary().RemoveKey( PdfName( "SigFlags" ) );
pdf_int64 val = 3;
pAcroForm->GetObject()->GetDictionary().AddKey( PdfName( "SigFlags" ), PdfObject( val ) );
}
if( pAcroForm->GetNeedAppearances() )
{
#if 0 /* TODO */
update_default_appearance_streams( pAcroForm );
#endif
pAcroForm->SetNeedAppearances( false );
}
PdfString name;
PdfObject* pExistingSigField = NULL;
PdfImage image( document );
image.LoadFromFile( ImgFile );
double dimgWidth = image.GetWidth();
double dimgHeight = image.GetHeight();
char fldName[96]; // use bigger buffer to make sure sprintf does not overflow
sprintf( fldName, "PodofoSignatureField%" PDF_FORMAT_INT64, static_cast( document->GetObjects().GetObjectCount() ) );
name = PdfString( fldName );
PdfPage* pPage = document->GetPage( annot_page );
if( !pPage )
PODOFO_RAISE_ERROR( ePdfError_PageNotFound );
double dPageHeight = pPage->GetPageSize().GetHeight();
double dPageWidth = pPage->GetPageSize().GetWidth();
PdfRect annot_rect;
annot_rect = PdfRect( rect.GetLeft(),
pPage->GetPageSize().GetHeight() - rect.GetBottom() - rect.GetHeight(),
dimgWidth,
dimgHeight );
PdfAnnotation* pAnnot = pPage->CreateAnnotation( ePdfAnnotation_Widget, annot_rect );
if( !pAnnot )
PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate annotation object" );
if( annot_print )
pAnnot->SetFlags( ePdfAnnotationFlags_Print );
else if( !field_name || !field_use_existing )
pAnnot->SetFlags( ePdfAnnotationFlags_Invisible | ePdfAnnotationFlags_Hidden );
PdfPainter painter;
try
{
painter.SetPage( /*&sigXObject*/pPage );
/* Workaround Adobe's reader error 'Expected a dict object.' when the stream
contains only one object which does Save()/Restore() on its own, like
the image XObject. */
painter.Save();
painter.Restore();
draw_annotation( *document, painter, image, annot_rect );
}
catch( PdfError & e )
{
if( painter.GetPage() )
{
try
{
painter.FinishPage();
}
catch( ... )
{
}
}
}
painter.FinishPage();
//pSignField = new PdfSignatureField( pAnnot, pAcroForm, document );
pSignField = new PdfSignatureField( pPage, annot_rect, document );
if( !pSignField )
PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate signature field object" );
PdfRect annotSize( 0.0, 0.0, dimgWidth, dimgHeight );
PdfXObject sigXObject( annotSize, document );
pSignField->SetAppearanceStream( &sigXObject );
// use large-enough buffer to hold the signature with the certificate
signer.SetSignatureSize( min_signature_size );
pSignField->SetFieldName( name );
pSignField->SetSignatureReason( PdfString( reinterpret_cast( reason ) ) );
pSignField->SetSignatureDate( /*sigData*/PdfDate() );
pSignField->SetSignature( *signer.GetSignatureBeacon() );
pSignField->SetBackgroundColorTransparent();
pSignField->SetBorderColorTransparent();
// The outPdfFile != NULL means that the write happens to a new file,
// which will be truncated first and then the content of the srcPdfFile
// will be copied into the document, follwed by the changes.
//signer.Seek(0);
document->WriteUpdate( &signer, true );
if( !signer.HasSignaturePosition() )
PODOFO_RAISE_ERROR_INFO( ePdfError_SignatureError, "Cannot find signature position in the document data" );
// Adjust ByteRange for signature
signer.AdjustByteRange();
// Read data for signature and count it
// We seek at the beginning of the file
signer.Seek( 0 );
sign_with_signer( signer, g_x509, g_pKey );
signer.Flush();
}
catch( PdfError & e )
{
}
if( pSignField )
delete pSignField;
}
上面的代码我用了两次,第一次签名无效。
如何在不使前一个签名失效的情况下添加两个数字签名?
画在右边PdfCanvas
在分析了示例 pdf 之后,您的第二个签名使您的第一个签名无效的原因变得清楚了:在签名过程中,您使用签名的小部件注释更改了页面的页面内容。
但是更改任何页面的内容都会使之前的签名失效!比照。 this answer 有关允许和不允许更改签名文档的详细信息。
确实:
PdfPainter painter;
try
{
painter.SetPage( /*&sigXObject*/pPage );
/* Workaround Adobe's reader error 'Expected a dict object.' when the stream
contains only one object which does Save()/Restore() on its own, like
the image XObject. */
painter.Save();
painter.Restore();
draw_annotation( *document, painter, image, annot_rect );
}
显然您在这里更改了页面内容本身。当在应用第二个签名的同时执行此代码时,第一个签名将失效。
您在评论中确认:
i use '&sigXObject' instead of 'pPage ',All two signatures are working! but the red seal disappeared
使用正确的坐标
关于你观察到的红色印章消失了:你在注释外观上绘制图像的坐标有误!
您使用页面坐标系的坐标,但您必须使用外观边界框给定的坐标系中的坐标。
因此,您的
painter.DrawImage( annot_rect.GetLeft(), annot_rect.GetBottom(), &image );
是错误的,请尝试
painter.DrawImage( 0, 0, &image );
因为你外表的边界框是
[ 0 0 151 151 ]
我遇到了同样的问题(在 C++ 中使用 podofo 开发)。 Insert multiple(2 times)数字签名后,发现pdf文件中有3个信息——字典:
如何在不使前一个签名失效的情况下添加两个数字签名?
谢谢!
我用记事本++打开文件,发现不一样
the first: 97 0 obj<</Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0) /Author(edison qian) /Keywords(GISerClub) /Creator(? M i c r o s o f t ? W o r d 2 0 1 3)
/CreationDate(D:20150601200942+08'00') /ModDate(D:20150601200942+08'00') /Producer(? M i c r o s o f t ? W o r d 2 0 1 3) >>
the second: 97 0 obj<</Author(edison qian)/CreationDate(D:20150601200942+08'00')/Creator(? M i c r o s o f t ? W o r d 2 0 1 3)/Keywords(GISerClub)
/ModDate(D:20190426155330+08'00')/Producer(? M i c r o s o f t ? W o r d 2 0 1 3)/Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0)>>
the third: 97 0 obj<</Author(edison qian)/CreationDate(D:20150601200942+08'00')/Creator(? M i c r o s o f t ? W o r d 2 0 1 3)/Keywords(GISerClub)
/ModDate(D:20190426155428+08'00')/Producer(? M i c r o s o f t ? W o r d 2 0 1 3)/Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0)>>
我的代码:
bool pdfSign(PdfMemDocument* document,PdfOutputDevice* outputDevice,PKCS12* p12,RSA* rsa,int npage,PdfRect rect,int min_signature_size,const char* ImgFile/*,PdfDate& sigData*/)
{
PdfInfo* pInfo = document->GetInfo();
TKeyMap itm = pInfo->GetObject()->GetDictionary().GetKeys();
PdfObject* pobj = pInfo->GetObject()->GetDictionary().GetKey(PdfName("ModDate"));
PdfString modDate = pobj->GetString();
string sDate = modDate.GetString();
string sutf8Date = modDate.GetStringUtf8();
PdfOutlines* pOutLine = document->GetOutlines();
TKeyMap itm2 = pOutLine->GetObject()->GetDictionary().GetKeys();
const char *field_name = NULL;
bool field_use_existing = false;
int annot_page = npage;
//double annot_left = 80.0, annot_top = 70.0, annot_width = 150.0, annot_height = 150.0;
bool annot_print = true;
const char *reason = "I agree";
int result = 0;
PdfSignatureField *pSignField = NULL;
try
{
PdfSignOutputDevice signer( outputDevice );
PdfAcroForm* pAcroForm = document->GetAcroForm();
if( !pAcroForm )
PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "acroForm == NULL" );
if( !pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) ||
!pAcroForm->GetObject()->GetDictionary().GetKey( PdfName( "SigFlags" ) )->IsNumber() ||
pAcroForm->GetObject()->GetDictionary().GetKeyAsLong( PdfName( "SigFlags" ) ) != 3 )
{
if( pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) )
pAcroForm->GetObject()->GetDictionary().RemoveKey( PdfName( "SigFlags" ) );
pdf_int64 val = 3;
pAcroForm->GetObject()->GetDictionary().AddKey( PdfName( "SigFlags" ), PdfObject( val ) );
}
if( pAcroForm->GetNeedAppearances() )
{
#if 0 /* TODO */
update_default_appearance_streams( pAcroForm );
#endif
pAcroForm->SetNeedAppearances( false );
}
PdfString name;
PdfObject* pExistingSigField = NULL;
PdfImage image( document );
image.LoadFromFile( ImgFile );
double dimgWidth = image.GetWidth();
double dimgHeight = image.GetHeight();
char fldName[96]; // use bigger buffer to make sure sprintf does not overflow
sprintf( fldName, "PodofoSignatureField%" PDF_FORMAT_INT64, static_cast( document->GetObjects().GetObjectCount() ) );
name = PdfString( fldName );
PdfPage* pPage = document->GetPage( annot_page );
if( !pPage )
PODOFO_RAISE_ERROR( ePdfError_PageNotFound );
double dPageHeight = pPage->GetPageSize().GetHeight();
double dPageWidth = pPage->GetPageSize().GetWidth();
PdfRect annot_rect;
annot_rect = PdfRect( rect.GetLeft(),
pPage->GetPageSize().GetHeight() - rect.GetBottom() - rect.GetHeight(),
dimgWidth,
dimgHeight );
PdfAnnotation* pAnnot = pPage->CreateAnnotation( ePdfAnnotation_Widget, annot_rect );
if( !pAnnot )
PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate annotation object" );
if( annot_print )
pAnnot->SetFlags( ePdfAnnotationFlags_Print );
else if( !field_name || !field_use_existing )
pAnnot->SetFlags( ePdfAnnotationFlags_Invisible | ePdfAnnotationFlags_Hidden );
PdfPainter painter;
try
{
painter.SetPage( /*&sigXObject*/pPage );
/* Workaround Adobe's reader error 'Expected a dict object.' when the stream
contains only one object which does Save()/Restore() on its own, like
the image XObject. */
painter.Save();
painter.Restore();
draw_annotation( *document, painter, image, annot_rect );
}
catch( PdfError & e )
{
if( painter.GetPage() )
{
try
{
painter.FinishPage();
}
catch( ... )
{
}
}
}
painter.FinishPage();
//pSignField = new PdfSignatureField( pAnnot, pAcroForm, document );
pSignField = new PdfSignatureField( pPage, annot_rect, document );
if( !pSignField )
PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate signature field object" );
PdfRect annotSize( 0.0, 0.0, dimgWidth, dimgHeight );
PdfXObject sigXObject( annotSize, document );
pSignField->SetAppearanceStream( &sigXObject );
// use large-enough buffer to hold the signature with the certificate
signer.SetSignatureSize( min_signature_size );
pSignField->SetFieldName( name );
pSignField->SetSignatureReason( PdfString( reinterpret_cast( reason ) ) );
pSignField->SetSignatureDate( /*sigData*/PdfDate() );
pSignField->SetSignature( *signer.GetSignatureBeacon() );
pSignField->SetBackgroundColorTransparent();
pSignField->SetBorderColorTransparent();
// The outPdfFile != NULL means that the write happens to a new file,
// which will be truncated first and then the content of the srcPdfFile
// will be copied into the document, follwed by the changes.
//signer.Seek(0);
document->WriteUpdate( &signer, true );
if( !signer.HasSignaturePosition() )
PODOFO_RAISE_ERROR_INFO( ePdfError_SignatureError, "Cannot find signature position in the document data" );
// Adjust ByteRange for signature
signer.AdjustByteRange();
// Read data for signature and count it
// We seek at the beginning of the file
signer.Seek( 0 );
sign_with_signer( signer, g_x509, g_pKey );
signer.Flush();
}
catch( PdfError & e )
{
}
if( pSignField )
delete pSignField;
}
上面的代码我用了两次,第一次签名无效。 如何在不使前一个签名失效的情况下添加两个数字签名?
画在右边PdfCanvas
在分析了示例 pdf 之后,您的第二个签名使您的第一个签名无效的原因变得清楚了:在签名过程中,您使用签名的小部件注释更改了页面的页面内容。
但是更改任何页面的内容都会使之前的签名失效!比照。 this answer 有关允许和不允许更改签名文档的详细信息。
确实:
PdfPainter painter;
try
{
painter.SetPage( /*&sigXObject*/pPage );
/* Workaround Adobe's reader error 'Expected a dict object.' when the stream
contains only one object which does Save()/Restore() on its own, like
the image XObject. */
painter.Save();
painter.Restore();
draw_annotation( *document, painter, image, annot_rect );
}
显然您在这里更改了页面内容本身。当在应用第二个签名的同时执行此代码时,第一个签名将失效。
您在评论中确认:
i use '&sigXObject' instead of 'pPage ',All two signatures are working! but the red seal disappeared
使用正确的坐标
关于你观察到的红色印章消失了:你在注释外观上绘制图像的坐标有误!
您使用页面坐标系的坐标,但您必须使用外观边界框给定的坐标系中的坐标。
因此,您的
painter.DrawImage( annot_rect.GetLeft(), annot_rect.GetBottom(), &image );
是错误的,请尝试
painter.DrawImage( 0, 0, &image );
因为你外表的边界框是
[ 0 0 151 151 ]