diff --git a/PdfFile/PdfFile.cpp b/PdfFile/PdfFile.cpp index b5579c4a5a..c9e7ba4da2 100644 --- a/PdfFile/PdfFile.cpp +++ b/PdfFile/PdfFile.cpp @@ -102,11 +102,23 @@ void CPdfFile::Close() else if (m_pInternal->pReader) m_pInternal->pReader->Close(); } -void CPdfFile::Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate) +void CPdfFile::Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath) { if (!m_pInternal->pWriter) return; - m_pInternal->pWriter->Sign(dX, dY, dW, dH, wsPicturePath, pCertificate); + m_pInternal->pWriter->Sign(dX, dY, dW, dH, wsPicturePath); +} +bool CPdfFile::PrepareSignature(BYTE** pDataToSign, DWORD& dwDataLength) +{ + if (!m_pInternal->pWriter) + return false; + return m_pInternal->pWriter->PrepareSignature(pDataToSign, dwDataLength); +} +bool CPdfFile::FinalizeSignature(BYTE* pSignedData, DWORD dwDataLength) +{ + if (!m_pInternal->pWriter) + return false; + return m_pInternal->pWriter->FinalizeSignature(pSignedData, dwDataLength); } void CPdfFile::SetDocumentInfo(const std::wstring& wsTitle, const std::wstring& wsCreator, const std::wstring& wsSubject, const std::wstring& wsKeywords) { @@ -134,6 +146,12 @@ bool CPdfFile::EditPdf(const std::wstring& wsDstFile) m_pInternal->pEditor = new CPdfEditor(m_pInternal->wsSrcFile, m_pInternal->wsPassword, wsDstFile, m_pInternal->pReader, m_pInternal->pWriter); return m_pInternal->pEditor->GetError() == 0; } +void CPdfFile::EditClose() +{ + if (m_pInternal->pEditor) + m_pInternal->pEditor->Close(); + RELEASEOBJECT(m_pInternal->pEditor); +} void CPdfFile::SetEditType(int nType) { if (!m_pInternal->pEditor) diff --git a/PdfFile/PdfFile.h b/PdfFile/PdfFile.h index cf5a9486e5..8f6d09e7a0 100644 --- a/PdfFile/PdfFile.h +++ b/PdfFile/PdfFile.h @@ -92,6 +92,7 @@ public: // --- EDIT --- // Переходит в режим редактирования. Pdf уже должен быть открыт на чтение - LoadFromFile/LoadFromMemory bool EditPdf(const std::wstring& wsDstFile = L""); + void EditClose(); void SetEditType(int nType); // Манипуляции со страницами возможны в режиме редактирования bool EditPage (int nPageIndex); @@ -159,7 +160,9 @@ public: void RotatePage (int nRotate); void SetPassword (const std::wstring& wsPassword); void SetDocumentID(const std::wstring& wsDocumentID); - void Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate); + void Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath); + bool PrepareSignature(BYTE** pDataToSign, DWORD& dwDataLength); + bool FinalizeSignature(BYTE* pSignedData, DWORD dwDataLength); void SetDocumentInfo(const std::wstring& wsTitle, const std::wstring& wsCreator, const std::wstring& wsSubject, const std::wstring& wsKeywords); void AddMetaData(const std::wstring& sMetaName, BYTE* pMetaData, DWORD nMetaLength); diff --git a/PdfFile/PdfWriter.cpp b/PdfFile/PdfWriter.cpp index 8046321e26..17b1736b01 100644 --- a/PdfFile/PdfWriter.cpp +++ b/PdfFile/PdfWriter.cpp @@ -3256,7 +3256,7 @@ void CPdfWriter::PageRotate(int nRotate) if (m_pPage) m_pPage->SetRotate(nRotate); } -void CPdfWriter::Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate) +void CPdfWriter::Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath) { PdfWriter::CImageDict* pImage = NULL; if (!wsPicturePath.empty()) @@ -3265,9 +3265,21 @@ void CPdfWriter::Sign(const double& dX, const double& dY, const double& dW, cons pImage = LoadImage(&oImage, 255); } - m_pDocument->Sign(PdfWriter::TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)), - pImage, pCertificate); + m_pDocument->Sign(PdfWriter::TRect(MM_2_PT(dX), m_pPage->GetHeight() - MM_2_PT(dY), MM_2_PT(dX + dW), m_pPage->GetHeight() - MM_2_PT(dY + dH)), pImage); } +bool CPdfWriter::PrepareSignature(BYTE** pDataToSign, DWORD& dwDataLength) +{ + if (!m_pDocument) + return false; + return m_pDocument->PrepareSignature(pDataToSign, dwDataLength); +} +bool CPdfWriter::FinalizeSignature(BYTE* pSignedData, DWORD dwDataLength) +{ + if (!m_pDocument) + return false; + return m_pDocument->FinalizeSignature(pSignedData, dwDataLength); +} + //---------------------------------------------------------------------------------------- // Внутренние функции //---------------------------------------------------------------------------------------- diff --git a/PdfFile/PdfWriter.h b/PdfFile/PdfWriter.h index 5efae9efd8..c73ebea75d 100644 --- a/PdfFile/PdfWriter.h +++ b/PdfFile/PdfWriter.h @@ -225,7 +225,9 @@ public: bool AddPage(int nPageIndex); bool EditClose(); void PageRotate(int nRotate); - void Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath, ICertificate* pCertificate); + void Sign(const double& dX, const double& dY, const double& dW, const double& dH, const std::wstring& wsPicturePath); + bool PrepareSignature(BYTE** pDataToSign, DWORD& dwDataLength); + bool FinalizeSignature(BYTE* pSignedData, DWORD dwDataLength); PdfWriter::CDocument* GetDocument(); PdfWriter::CPage* GetPage(); IRenderer* GetRenderer(); diff --git a/PdfFile/SrcWriter/Document.cpp b/PdfFile/SrcWriter/Document.cpp index 19af4c9bf1..d33b92218d 100644 --- a/PdfFile/SrcWriter/Document.cpp +++ b/PdfFile/SrcWriter/Document.cpp @@ -1950,96 +1950,157 @@ namespace PdfWriter unsigned int nSizeXRef = m_pXref->GetSizeXRef() + (bNeedStreamXRef ? 1 : 0); m_pXref = m_pLastXref; Sign(wsPath, nSizeXRef, bNeedStreamXRef); - RELEASEOBJECT(m_pEncryptDict); + // TODO проверить RELEASEOBJECT(m_pEncryptDict); return true; } - void CDocument::Sign(const TRect& oRect, CImageDict* pImage, ICertificate* pCertificate) + void CDocument::Sign(const TRect& oRect, CImageDict* pImage) { - m_vSignatures.push_back({ oRect, m_pCurPage ? m_pCurPage : m_pPageTree->GetPage(0), pImage, pCertificate }); + m_vSignatures.push_back(new TSignatureInfo(oRect, m_pCurPage ? m_pCurPage : m_pPageTree->GetPage(0), pImage)); + } + bool CDocument::PrepareSignature(BYTE** pDataToSign, DWORD& dwDataLength) + { + // Сначала нужно сохранить основной файл + // Это должно быть сделано в AddToFile или SaveToFile ПЕРЕД вызовом этого метода + + if (m_vSignatures.empty()) + return false; + + TSignatureInfo* pSI = m_vSignatures[0]; + + std::wstring wsPath = pSI->wsPath; + if (wsPath.empty()) + return false; + + unsigned int nSizeXRef = pSI->nSizeXRef; + bool bNeedStreamXRef = pSI->bNeedStreamXRef; + + // Создаем новый XRef для этой подписи + CXref* pXrefBefore = m_pXref; + m_pXref = new CXref(this, nSizeXRef); + if (!m_pXref) + { + m_pXref = pXrefBefore; + return false; + } + + // Создаем поле подписи + CSignatureField* pField = CreateSignatureField(); + if (!pField) + { + delete m_pXref; + m_pXref = pXrefBefore; + return false; + } + + // Настраиваем поле + pSI->pField = pField; + m_pAcroForm->Add("SigFlags", 3); + pField->GetSignatureDict()->SetDate(); + pField->AddPageRect(pSI->pPage, pSI->oRect); + pField->Add("F", 132); + pField->SetFieldName("Sig" + std::to_string(++m_unFormFields)); + if (pSI->pImage) + pField->SetAppearance(pSI->pImage); + + // Открываем файл для дозаписи + CFileStream* pStream = new CFileStream(); + if (!pStream || !pStream->OpenFile(wsPath, false)) + { + delete m_pXref; + m_pXref = pXrefBefore; + return false; + } + + // Вычисляем размер для Contents + unsigned int nContentsSize = 7000 + pStream->Size() / 1000 + 1000; + if (nContentsSize < 5000) + nContentsSize = 5000; + if (nContentsSize > 20000) + nContentsSize = 20000; + pField->GetSignatureDict()->SetContentsSize(nContentsSize); + + // Записываем XRef и получаем информацию о расположении + CXref* pXrefCatalog = new CXref(this, m_pCatalog->GetObjId()); + if (pXrefCatalog) + { + pXrefCatalog->Add(m_pCatalog->Copy(), m_pCatalog->GetGenNo()); + pXrefCatalog->SetPrev(m_pXref); + } + + CXref* pXrefPage = new CXref(this, pSI->pPage->GetObjId()); + if (pXrefPage) + { + pXrefPage->Add(pSI->pPage->Copy(), pSI->pPage->GetGenNo()); + pXrefPage->SetPrev(pXrefCatalog); + } + + CXref* pXref = new CXref(this, 0, 65535); + if (pXref) + { + pXref->SetPrev(pXrefPage); + CDictObject* pTrailer = pXref->GetTrailer(); + m_pTrailer->Copy(pTrailer); + + CEncrypt* pEncrypt = NULL; + if (m_pEncryptDict) + pEncrypt = m_pEncryptDict->GetEncrypt(); + + pXref->WriteToStream(pStream, pEncrypt, bNeedStreamXRef); + pSI->pXref = pXref; + } + + pField->GetSignatureDict()->WriteToStream(pStream, pStream->Size(), pDataToSign, dwDataLength); + + // Восстанавливаем XRef + m_pXref = pXrefBefore; + + delete pStream; + + return true; + } + bool CDocument::FinalizeSignature(BYTE* pSignedData, DWORD dwDataLength) + { + if (m_vSignatures.empty()) + return false; + + TSignatureInfo* pSI = m_vSignatures[0]; + bool bNeedStreamXRef = pSI->bNeedStreamXRef; + std::wstring wsPath = pSI->wsPath; + if (wsPath.empty() || !pSI->pField) + return false; + + CFileStream* pStream = new CFileStream(); + if (!pStream || !pStream->OpenFile(wsPath, false)) + { + delete pStream; + return false; + } + + if (!pSI->pField->GetSignatureDict() || !pSI->pField->GetSignatureDict()->FinalizeSignature(pStream, pSignedData, dwDataLength)) + { + delete pStream; + return false; + } + + CXref* pXref = pSI->pXref; + delete pStream; + delete pSI; + + m_vSignatures.pop_front(); + Sign(wsPath, pXref->GetSizeXRef() + (bNeedStreamXRef ? 1 : 0), bNeedStreamXRef); + delete pXref; + + return true; } void CDocument::Sign(const std::wstring& wsPath, unsigned int nSizeXRef, bool bNeedStreamXRef) { - unsigned int nPrevAddr = m_pXref->GetPrevAddr(); - std::vector vXRefForWrite; - for (unsigned int i = 0; i < m_vSignatures.size(); i++) + if (!m_vSignatures.empty()) { - CXref* pXrefBefore = m_pXref; - m_pXref = new CXref(this, nSizeXRef); - if (!m_pXref) - { - m_pXref = pXrefBefore; - continue; - } - m_pXref->SetPrevAddr(nPrevAddr); - - CSignatureField* pField = CreateSignatureField(); - if (!pField) - { - RELEASEOBJECT(m_pXref); - m_pXref = pXrefBefore; - continue; - } - - m_pAcroForm->Add("SigFlags", 3); - pField->GetSignatureDict()->SetCert(m_vSignatures[i].pCertificate); - pField->GetSignatureDict()->SetDate(); - pField->AddPageRect(m_vSignatures[i].pPage, m_vSignatures[i].oRect); - pField->Add("F", 132); - pField->SetFieldName("Sig" + std::to_string(i + m_unFormFields + 1)); - if (m_vSignatures[i].pImage) - pField->SetAppearance(m_vSignatures[i].pImage); - - CFileStream* pStream = new CFileStream(); - if (!pStream || !pStream->OpenFile(wsPath, false)) - { - RELEASEOBJECT(m_pXref); - m_pXref = pXrefBefore; - continue; - } - - CXref* pXrefCatalog = new CXref(this, m_pCatalog->GetObjId()); - if (pXrefCatalog) - { - pXrefCatalog->Add(m_pCatalog->Copy(), m_pCatalog->GetGenNo()); - pXrefCatalog->SetPrev(m_pXref); - } - - CXref* pXrefPage = new CXref(this, m_vSignatures[i].pPage->GetObjId()); - if (pXrefPage) - { - pXrefPage->Add(m_vSignatures[i].pPage->Copy(), m_vSignatures[i].pPage->GetGenNo()); - pXrefPage->SetPrev(pXrefCatalog); - } - - CXref* pXref = new CXref(this, 0, 65535); - if (pXref) - { - pXref->SetPrev(pXrefPage); - CDictObject* pTrailer = pXref->GetTrailer(); - m_pTrailer->Copy(pTrailer); - - CEncrypt* pEncrypt = NULL; - if (m_pEncryptDict) - pEncrypt = m_pEncryptDict->GetEncrypt(); - - pXref->WriteToStream(pStream, pEncrypt, bNeedStreamXRef); - nPrevAddr = pXref->GetPrevAddr(); - nSizeXRef = m_pXref->GetSizeXRef(); - vXRefForWrite.push_back(pXref); - } - - RELEASEOBJECT(pStream); - pStream = new CFileStream(); - if (pStream && pStream->OpenFile(wsPath, false)) - pField->GetSignatureDict()->WriteToStream(pStream, pStream->Size()); - - m_pXref = pXrefBefore; - RELEASEOBJECT(pStream); + m_vSignatures[0]->wsPath = wsPath; + m_vSignatures[0]->nSizeXRef = nSizeXRef; + m_vSignatures[0]->bNeedStreamXRef = bNeedStreamXRef; } - for (CXref* XRef : vXRefForWrite) - RELEASEOBJECT(XRef); - vXRefForWrite.clear(); } void CDocument::AddShapeXML(const std::string& sXML) { diff --git a/PdfFile/SrcWriter/Document.h b/PdfFile/SrcWriter/Document.h index f4506fc5d5..8f394530c7 100644 --- a/PdfFile/SrcWriter/Document.h +++ b/PdfFile/SrcWriter/Document.h @@ -33,6 +33,7 @@ #define _PDF_WRITER_SRC_DOCUMENT_H #include +#include #include #include "Types.h" @@ -195,7 +196,9 @@ namespace PdfWriter bool AddToFile(const std::wstring& wsPath, CXref* pXref, CDictObject* pTrailer, CXref* pInfoXref, CInfoDict* pInfo); void AddObject(CObjectBase* pObj); bool MovePage(int nPageIndex, int nPos); - void Sign(const TRect& oRect, CImageDict* pImage, ICertificate* pCert); + void Sign(const TRect& oRect, CImageDict* pImage); + bool PrepareSignature(BYTE** pDataToSign, DWORD& dwDataLength); + bool FinalizeSignature(BYTE* pSignedData, DWORD dwDataLength); bool EditAnnot (CXref* pXref, CAnnotation* pAnnot, int nID); void AddParent(int nID, CDictObject* pParent); CDictObject* CreateParent(int nID); @@ -255,18 +258,27 @@ namespace PdfWriter }; struct TSignatureInfo { - TSignatureInfo(const TRect& _oRect, CPage* _pPage, CImageDict* _pImage, ICertificate* _pCertificate) + TSignatureInfo(const TRect& _oRect, CPage* _pPage, CImageDict* _pImage) { oRect = _oRect; pPage = _pPage; pImage = _pImage; - pCertificate = _pCertificate; + + nSizeXRef = 0; + bNeedStreamXRef = false; + pField = NULL; + pXref = NULL; } TRect oRect; CPage* pPage; CImageDict* pImage; - ICertificate* pCertificate; + + std::wstring wsPath; + unsigned int nSizeXRef; + bool bNeedStreamXRef; + CSignatureField* pField; + CXref* pXref; }; struct TImageInfo { @@ -296,7 +308,7 @@ namespace PdfWriter CStreamData* m_pMetaData; bool m_bEncrypt; CEncryptDict* m_pEncryptDict; - std::vector m_vSignatures; + std::deque m_vSignatures; std::vector m_vImages; unsigned int m_unFormFields; unsigned int m_unCompressMode; diff --git a/PdfFile/SrcWriter/EncryptDictionary.cpp b/PdfFile/SrcWriter/EncryptDictionary.cpp index 74bf9a61d6..1b29586f16 100644 --- a/PdfFile/SrcWriter/EncryptDictionary.cpp +++ b/PdfFile/SrcWriter/EncryptDictionary.cpp @@ -223,32 +223,6 @@ namespace PdfWriter Add("Filter", "Adobe.PPKLite"); Add("SubFilter", "adbe.pkcs7.detached"); - unsigned int unDigestLength = 15000; - BYTE* pDigest = new BYTE[unDigestLength]; - memset(pDigest, 0, unDigestLength); - Add("Contents", new CBinaryObject(pDigest, unDigestLength)); - RELEASEARRAYOBJECTS(pDigest); - - CArrayObject* pByteRange = new CArrayObject(); - if (!pByteRange) - return; - Add("ByteRange", pByteRange); - pByteRange->Add(0); - pByteRange->Add(1234567890); - pByteRange->Add(1234567890); - pByteRange->Add(1234567890); - - // Reference - Массив справочных словарей сигнатур - - // Changes - Массив из трех чисел, который указывает изменения в документе в порядке: количество измененных страниц, - // количество измененных полей и количество заполненных полей - // Порядок подписей определяется значением ByteRange. Поскольку каждая подпись приводит к добавочному сохранению, - // более поздние подписи имеют большее значение длины - - // Prop_Build - Словарь, который может использоваться обработчиком подписи для записи информации о состоянии компьютерной среды, - // используемой для подписи, такой как имя обработчика, используемого для создания подписи, дата сборки программного обеспечения, - // версия, и операционная система. Спецификация словаря PDF Signature Build содержит рекомендации по использованию этого словаря - m_nLen1 = 0; m_nOffset2 = 0; m_nByteRangeBegin = 0; @@ -259,40 +233,33 @@ namespace PdfWriter } void CSignatureDict::WriteToStream(CStream* pStream, CEncrypt* pEncrypt) { - for (auto const &oIter : m_mList) + for (std::map::const_iterator oIter = m_mList.begin(); oIter != m_mList.end(); ++oIter) { - CObjectBase* pObject = oIter.second; - if (!pObject) + CObjectBase* pObject = oIter->second; + if (!pObject || pObject->IsHidden()) continue; - if (pObject->IsHidden()) + int nBegin, nEnd; + pStream->WriteEscapeName(oIter->first.c_str()); + pStream->WriteChar(' '); + nBegin = pStream->Tell(); + // Цифровая подпись не шифруется + pStream->Write(pObject, oIter->first == "Contents" ? NULL : pEncrypt); + nEnd = pStream->Tell(); + pStream->WriteStr("\012"); + if (oIter->first == "Contents") { - // ничего не делаем + m_nLen1 = nBegin; + m_nOffset2 = nEnd; } - else + if (oIter->first == "ByteRange") { - int nBegin, nEnd; - pStream->WriteEscapeName(oIter.first.c_str()); - pStream->WriteChar(' '); - nBegin = pStream->Tell(); - // Цифровая подпись не шифруется - pStream->Write(pObject, oIter.first == "Contents" ? NULL : pEncrypt); - nEnd = pStream->Tell(); - pStream->WriteStr("\012"); - if (oIter.first == "Contents") - { - m_nLen1 = nBegin; - m_nOffset2 = nEnd; - } - if (oIter.first == "ByteRange") - { - m_nByteRangeBegin = nBegin; - m_nByteRangeEnd = nEnd; - } + m_nByteRangeBegin = nBegin; + m_nByteRangeEnd = nEnd; } } } - void CSignatureDict::WriteToStream(CStream* pStream, int nFileEnd) + void CSignatureDict::WriteToStream(CStream* pStream, int nFileEnd, BYTE** pDataForSignature, DWORD& dwLenDataForSignature) { // Запись ByteRange if (m_nByteRangeBegin > 0 && m_nByteRangeEnd > 0 && m_nByteRangeBegin < m_nByteRangeEnd && m_nByteRangeEnd < nFileEnd) @@ -325,16 +292,16 @@ namespace PdfWriter RELEASEOBJECT(pByteRange); } // Запись Contents - if (m_pCertificate && m_nLen1 > 0 && m_nOffset2 > 0 && m_nLen1 < m_nOffset2 && m_nOffset2 < nFileEnd) + if (m_nLen1 > 0 && m_nOffset2 > 0 && m_nLen1 < m_nOffset2 && m_nOffset2 < nFileEnd) { - DWORD dwLenDataForSignature = m_nLen1 + nFileEnd - m_nOffset2; - BYTE* pDataForSignature = new BYTE[dwLenDataForSignature]; - if (!pDataForSignature) + dwLenDataForSignature = m_nLen1 + nFileEnd - m_nOffset2; + *pDataForSignature = new BYTE[dwLenDataForSignature]; + if (!*pDataForSignature) return; pStream->Seek(0, EWhenceMode::SeekSet); unsigned int dwLenReadData = m_nLen1; - pStream->Read(pDataForSignature, &dwLenReadData); + pStream->Read(*pDataForSignature, &dwLenReadData); if ((int)dwLenReadData != m_nLen1) { RELEASEARRAYOBJECTS(pDataForSignature); @@ -343,40 +310,69 @@ namespace PdfWriter pStream->Seek(m_nOffset2, EWhenceMode::SeekSet); dwLenReadData = nFileEnd - m_nOffset2; - pStream->Read(pDataForSignature + m_nLen1, &dwLenReadData); + pStream->Read(*pDataForSignature + m_nLen1, &dwLenReadData); if ((int)dwLenReadData != nFileEnd - m_nOffset2) { RELEASEARRAYOBJECTS(pDataForSignature); return; } + /* BYTE* pDatatoWrite = NULL; unsigned int dwLenDatatoWrite; m_pCertificate->SignPKCS7(pDataForSignature, dwLenDataForSignature, pDatatoWrite, dwLenDatatoWrite); RELEASEARRAYOBJECTS(pDataForSignature); if (!pDatatoWrite) return; - - pStream->Seek(m_nLen1, EWhenceMode::SeekSet); - CBinaryObject* pContents = new CBinaryObject(pDatatoWrite, dwLenDatatoWrite); - RELEASEARRAYOBJECTS(pDatatoWrite); - if (!pContents) - return; - // Цифровая подпись не шифруется - pStream->Write(pContents, NULL); - RELEASEOBJECT(pContents); - - // Стереть лишний > - BYTE cChar = '0'; - pStream->Seek(pStream->Tell() - 1, EWhenceMode::SeekSet); - pStream->Write(&cChar, 1); + */ } } - void CSignatureDict::SetCert(ICertificate* pCert) - { - m_pCertificate = pCert; - } - void CSignatureDict::SetName(const std::string& sName) + bool CSignatureDict::FinalizeSignature(CStream* pStream, BYTE* pSignedData, DWORD dwDataLength) + { + if (!pSignedData) + return false; + + // Записываем подписанные данные в Contents + if (dwDataLength > m_nContentsSize) + { + // Подпись не влезает! Ошибка расчета размера + return false; + } + + pStream->Seek(m_nLen1, EWhenceMode::SeekSet); + CBinaryObject* pContents = new CBinaryObject(pSignedData, dwDataLength); + if (!pContents) + return false; + + // Цифровая подпись не шифруется + pStream->Write(pContents, NULL); + delete pContents; + + // Стираем лишний '>' если нужно + BYTE cChar = '0'; + pStream->Seek(pStream->Tell() - 1, EWhenceMode::SeekSet); + pStream->Write(&cChar, 1); + + return true; + } + void CSignatureDict::SetContentsSize(unsigned int nSize) + { + m_nContentsSize = nSize; + + BYTE* pDigest = new BYTE[m_nContentsSize]; + memset(pDigest, 0, m_nContentsSize); + Add("Contents", new CBinaryObject(pDigest, m_nContentsSize, false)); + + CArrayObject* pByteRange = new CArrayObject(); + if (!pByteRange) + return; + Add("ByteRange", pByteRange); + pByteRange->Add(0); + pByteRange->Add(1234567890); + pByteRange->Add(1234567890); + pByteRange->Add(1234567890); + } + void CSignatureDict::SetName(const std::string& sName) { // Name - Cтрока, Имя лица или органа, подписавшего документ. // Значение следует использовать когда невозможно извлечь имя из подписи или сертификата подписавшего. diff --git a/PdfFile/SrcWriter/EncryptDictionary.h b/PdfFile/SrcWriter/EncryptDictionary.h index d296223e08..e5ad3cbaec 100644 --- a/PdfFile/SrcWriter/EncryptDictionary.h +++ b/PdfFile/SrcWriter/EncryptDictionary.h @@ -34,8 +34,6 @@ #include "Objects.h" -#include "../../DesktopEditor/xmlsec/src/include/Certificate.h" - namespace PdfWriter { class CEncrypt; @@ -78,18 +76,19 @@ namespace PdfWriter } void WriteToStream(CStream* pStream, CEncrypt* pEncrypt) override; - void WriteToStream(CStream* pStream, int nFileEnd); - void SetCert(ICertificate* pCert); + void WriteToStream(CStream* pStream, int nFileEnd, BYTE** pDataToSign, DWORD& dwDataLength); + bool FinalizeSignature(CStream* pStream, BYTE* pSignedData, DWORD dwDataLength); + void SetContentsSize(unsigned int nSize); void SetName(const std::string& sName); void SetReason(const std::string& sReason); void SetContact(const std::string& sContacts); void SetDate(); private: - ICertificate* m_pCertificate; + unsigned int m_nContentsSize; // Размер Contents - int m_nLen1; // Длина первого интервала сигнатуры - int m_nOffset2; // Начало второго интервала сигнатуры + int m_nLen1; // Длина первого интервала + int m_nOffset2; // Начало второго интервала int m_nByteRangeBegin; // Смещение начала массива ByteRange int m_nByteRangeEnd; // Смещение конца массива ByteRange diff --git a/PdfFile/test/test.cpp b/PdfFile/test/test.cpp index 820d9bbb58..e7d2a3daf4 100644 --- a/PdfFile/test/test.cpp +++ b/PdfFile/test/test.cpp @@ -524,7 +524,7 @@ TEST_F(CPdfFileTest, EditPdf) TEST_F(CPdfFileTest, EditPdfFromBase64) { - //GTEST_SKIP(); + GTEST_SKIP(); NSFonts::NSApplicationFontStream::SetGlobalMemoryStorage(NSFonts::NSApplicationFontStream::CreateDefaultGlobalMemoryStorage()); @@ -602,22 +602,93 @@ TEST_F(CPdfFileTest, EditPdfFromBin) TEST_F(CPdfFileTest, EditPdfSign) { - GTEST_SKIP(); + //GTEST_SKIP(); LoadFromFile(); ASSERT_TRUE(pdfFile->EditPdf(wsDstFile)); - ICertificate* pCertificate = GetCertificate(); - ASSERT_TRUE(pCertificate); - EXPECT_TRUE(pdfFile->EditPage(0)); { - pdfFile->Sign(10, 10, 100, 100, NSFile::GetProcessDirectory() + L"/test.jpeg", pCertificate); + pdfFile->Sign(10, 10, 100, 100, NSFile::GetProcessDirectory() + L"/test.jpeg"); + pdfFile->Sign(10, 150, 100, 100, NSFile::GetProcessDirectory() + L"/test.jpeg"); + pdfFile->Sign(10, 300, 100, 100, NSFile::GetProcessDirectory() + L"/test.jpeg"); + } + + // Для цифровой подписи важно предварительно pdfFile->EditClose, в остальных случаях pdfFile->Close() сделает тоже самое + pdfFile->EditClose(); + + // EditPdf & EditClose || CreatePdf & SaveToFile + // И только после подготовка данных для подписания, подписываем, запись подписи + for (int i = 0; i < 3; ++i) + { + BYTE* pDataToSign = NULL; + DWORD dwDataLength = 0; + + // Получили данные для подписания + pdfFile->PrepareSignature(&pDataToSign, dwDataLength); + + ICertificate* pCertificate = GetCertificate(); + ASSERT_TRUE(pCertificate); + + BYTE* pDatatoWrite = NULL; + unsigned int dwLenDatatoWrite = 0; + // Предположим, что для подписи 1 произошло не успешное подписание, и данные остались пустыми + pCertificate->SignPKCS7(pDataToSign, dwDataLength, pDatatoWrite, dwLenDatatoWrite); + + // Обязательно FinalizeSignature - он либо заполнит данные, либо сделает подпись пустой + pdfFile->FinalizeSignature(pDatatoWrite, dwLenDatatoWrite); + + RELEASEOBJECT(pCertificate); } pdfFile->Close(); +} - RELEASEOBJECT(pCertificate); +TEST_F(CPdfFileTest, PdfToPdfSign) +{ + GTEST_SKIP(); + + LoadFromFile(); + pdfFile->CreatePdf(); + + double dPageDpiX, dPageDpiY, dW, dH; + int nPages = pdfFile->GetPagesCount(); + for (int i = 0; i < nPages; i++) + { + pdfFile->NewPage(); + + pdfFile->GetPageInfo(i, &dW, &dH, &dPageDpiX, &dPageDpiY); + pdfFile->put_Width( dW / dPageDpiX * 25.4); + pdfFile->put_Height(dH / dPageDpiY * 25.4); + + pdfFile->DrawPageOnRenderer(pdfFile, i, NULL); + + pdfFile->Sign(10, 10, 100, 100, NSFile::GetProcessDirectory() + L"/test.jpeg"); + } + + pdfFile->SaveToFile(wsDstFile); + + for (int i = 0; i < nPages; ++i) + { + BYTE* pDataToSign = NULL; + DWORD dwDataLength = 0; + + pdfFile->PrepareSignature(&pDataToSign, dwDataLength); + + ICertificate* pCertificate = GetCertificate(); + ASSERT_TRUE(pCertificate); + + BYTE* pDatatoWrite = NULL; + unsigned int dwLenDatatoWrite = 0; + if (i % 2 == 0) + pCertificate->SignPKCS7(pDataToSign, dwDataLength, pDatatoWrite, dwLenDatatoWrite); + + pdfFile->FinalizeSignature(pDatatoWrite, dwLenDatatoWrite); + + RELEASEOBJECT(pCertificate); + } + + pdfFile->Close(); } TEST_F(CPdfFileTest, PrintPdf)