diff options
author | Philipp Lohmann [pl] <Philipp.Lohmann@Oracle.COM> | 2010-09-24 14:28:04 +0200 |
---|---|---|
committer | Philipp Lohmann [pl] <Philipp.Lohmann@Oracle.COM> | 2010-09-24 14:28:04 +0200 |
commit | 4d25643942f30ad94b853a65338098d842767ed8 (patch) | |
tree | 7d19291fc57940703b55a3a0ffba133849d10fe0 /vcl | |
parent | a555527edb34036835b167f0b3b7f6d515f098c4 (diff) |
step1: put encrpytion parameters into PDFContext
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/vcl/pdfwriter.hxx | 82 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter.cxx | 20 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 817 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.hxx | 170 |
4 files changed, 607 insertions, 482 deletions
diff --git a/vcl/inc/vcl/pdfwriter.hxx b/vcl/inc/vcl/pdfwriter.hxx index 419814e5ce97..cbb9c7c2fe93 100644 --- a/vcl/inc/vcl/pdfwriter.hxx +++ b/vcl/inc/vcl/pdfwriter.hxx @@ -61,16 +61,6 @@ class Wallpaper; namespace vcl { -struct PDFDocInfo -{ - String Title; // document title - String Author; // document author - String Subject; // subject - String Keywords; // keywords - String Creator; // application that created the original document - String Producer; // OpenOffice -}; - struct PDFNote { String Title; // optional title for the popup containing the note @@ -468,7 +458,7 @@ public: FitVisible, ActionZoom }; -// These emuns are treated as integer while reading/writing to configuration +// These enums are treated as integer while reading/writing to configuration enum PDFPageLayout { DefaultLayout, @@ -489,20 +479,35 @@ public: /* The following structure describes the permissions used in PDF security */ - struct PDFSecPermissions + struct PDFEncryptionProperties { -//for both 40 and 128 bit security, see 3.5.2 PDF v 1.4 table 3.15, v 1.5 and v 1.6 table 3.20. - bool CanPrintTheDocument; + + bool Security128bit; // true to select 128 bit encryption, false for 40 bit + //for both 40 and 128 bit security, see 3.5.2 PDF v 1.4 table 3.15, v 1.5 and v 1.6 table 3.20. + bool CanPrintTheDocument; bool CanModifyTheContent; bool CanCopyOrExtract; bool CanAddOrModify; -//for revision 3 (bit 128 security) only + //for revision 3 (bit 128 security) only bool CanFillInteractive; bool CanExtractForAccessibility; bool CanAssemble; bool CanPrintFull; -//permission default set for 128 bit, accessibility only - PDFSecPermissions() : + + // encryption will only happen if EncryptionKey is not empty + // EncryptionKey is actually a construct out of OValue, UValue and DocumentIdentifier + // if these do not match, behavior is undefined, most likely an invalid PDF will be produced + // OValue, UValue, EncryptionKey and DocumentIdentifier can be computed from + // PDFDocInfo, Owner password and User password usend the InitEncryption method which + // implements the algorithms described in the PDF reference chapter 3.5: Encryption + std::vector<sal_uInt8> OValue; + std::vector<sal_uInt8> UValue; + std::vector<sal_uInt8> EncryptionKey; + std::vector<sal_uInt8> DocumentIdentifier; + + //permission default set for 128 bit, accessibility only + PDFEncryptionProperties() : + Security128bit ( true ), CanPrintTheDocument ( false ), CanModifyTheContent ( false ), CanCopyOrExtract ( false ), @@ -512,6 +517,20 @@ The following structure describes the permissions used in PDF security CanAssemble ( false ), CanPrintFull ( false ) {} + + + bool Encrypt() const + { return ! OValue.empty() && ! UValue.empty() && ! DocumentIdentifier.empty(); } + }; + + struct PDFDocInfo + { + String Title; // document title + String Author; // document author + String Subject; // subject + String Keywords; // keywords + String Creator; // application that created the original document + String Producer; // OpenOffice }; struct PDFWriterContext @@ -570,12 +589,8 @@ The following structure describes the permissions used in PDF security sal_Int32 InitialPage; sal_Int32 OpenBookmarkLevels; // -1 means all levels - struct PDFSecPermissions AccessPermissions; - - bool Encrypt; // main encryption flag, must be true to encript - bool Security128bit; // true to select 128 bit encryption, false for 40 bit - rtl::OUString OwnerPassword; // owner password for PDF, in clear text - rtl::OUString UserPassword; // user password for PDF, in clear text + PDFWriter::PDFEncryptionProperties Encryption; + PDFWriter::PDFDocInfo DocumentInfo; com::sun::star::lang::Locale DocumentLocale; // defines the document default language @@ -604,9 +619,7 @@ The following structure describes the permissions used in PDF security FirstPageLeft( false ), InitialPage( 1 ), OpenBookmarkLevels( -1 ), - AccessPermissions( ), - Encrypt( false ), - Security128bit( true ) + Encryption() {} }; @@ -636,17 +649,6 @@ The following structure describes the permissions used in PDF security */ sal_Int32 NewPage( sal_Int32 nPageWidth = 0, sal_Int32 nPageHeight = 0, Orientation eOrientation = Inherit ); - /* - * set document info; due to the use of document information in building the PDF document ID, must be called before - * emitting anything. - */ - void SetDocInfo( const PDFDocInfo& rInfo ); - - /* - * get currently set document info - */ - const PDFDocInfo& GetDocInfo() const; - /* sets the document locale originally passed with the context to a new value * only affects the output if used before calling <code>Emit/code>. */ @@ -664,6 +666,12 @@ The following structure describes the permissions used in PDF security PDFVersion GetVersion() const; + static bool InitEncryption( PDFWriter::PDFEncryptionProperties& io_rProperties, + const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + const PDFWriter::PDFDocInfo& i_rDocInfo + ); + /* functions for graphics state */ /* flag values: see vcl/outdev.hxx */ void Push( USHORT nFlags = 0xffff ); diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx index 5dcce25a0315..3b5e70d938a8 100644 --- a/vcl/source/gdi/pdfwriter.cxx +++ b/vcl/source/gdi/pdfwriter.cxx @@ -69,16 +69,6 @@ PDFWriter::PDFVersion PDFWriter::GetVersion() const return ((PDFWriterImpl*)pImplementation)->getVersion(); } -void PDFWriter::SetDocInfo( const PDFDocInfo& rInfo ) -{ - ((PDFWriterImpl*)pImplementation)->setDocInfo( rInfo ); -} - -const PDFDocInfo& PDFWriter::GetDocInfo() const -{ - return ((PDFWriterImpl*)pImplementation)->getDocInfo(); -} - void PDFWriter::SetDocumentLocale( const com::sun::star::lang::Locale& rLoc ) { ((PDFWriterImpl*)pImplementation)->setDocumentLocale( rLoc ); @@ -569,3 +559,13 @@ std::set< PDFWriter::ErrorCode > PDFWriter::GetErrors() { return ((PDFWriterImpl*)pImplementation)->getErrors(); } + +bool PDFWriter::InitEncryption( PDFWriter::PDFEncryptionProperties& io_rProperties, + const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + const PDFWriter::PDFDocInfo& i_rDocInfo + ) +{ + return PDFWriterImpl::initEncryption( io_rProperties, i_rOwnerPassword, i_rUserPassword, i_rDocInfo ); +} + diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 09cf1734eb6f..ff415ccfa98c 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -113,12 +113,10 @@ void doTestCode() aContext.Version = PDFWriter::PDF_1_4; aContext.Tagged = true; aContext.InitialPage = 2; + aContext.DocumentInfo.Title = OUString( RTL_CONSTASCII_USTRINGPARAM( "PDF export test document" ) ); + aContext.DocumentInfo.Producer = OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL" ) ); PDFWriter aWriter( aContext ); - PDFDocInfo aDocInfo; - aDocInfo.Title = OUString( RTL_CONSTASCII_USTRINGPARAM( "PDF export test document" ) ); - aDocInfo.Producer = OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL" ) ); - aWriter.SetDocInfo( aDocInfo ); aWriter.NewPage( 595, 842 ); aWriter.BeginStructureElement( PDFWriter::Document ); // set duration of 3 sec for first page @@ -496,6 +494,12 @@ static inline double pixelToPoint( sal_Int32 px ) { return double(px)/fDivisor; static inline double pixelToPoint( double px ) { return px/fDivisor; } static inline sal_Int32 pointToPixel( double pt ) { return sal_Int32(pt*fDivisor); } +const sal_uInt8 PDFWriterImpl::s_nPadString[32] = +{ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A +}; + static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer ) { static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -1714,9 +1718,6 @@ PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext ) m_aCipher( (rtlCipher)NULL ), m_aDigest( NULL ), m_bEncryptThisStream( false ), - m_aDocID( 32 ), - m_aCreationDateString( 64 ), - m_aCreationMetaDateString( 64 ), m_pEncryptionBuffer( NULL ), m_nEncryptionBufferSize( 0 ), m_bIsPDF_A1( false ) @@ -1758,14 +1759,32 @@ PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext ) m_bOpen = true; -/* prepare the cypher engine, can be done in CTOR, free in DTOR */ + /* prepare the cypher engine, can be done in CTOR, free in DTOR */ m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); m_aDigest = rtl_digest_createMD5(); -/* the size of the Codec default maximum */ + /* the size of the Codec default maximum */ checkEncryptionBufferSize( 0x4000 ); + if( m_aContext.Encryption.Encrypt() ) + { + // sanity check + if( m_aContext.Encryption.OValue.size() != ENCRYPTED_PWD_SIZE || + m_aContext.Encryption.UValue.size() != ENCRYPTED_PWD_SIZE || + m_aContext.Encryption.EncryptionKey.size() != MAXIMUM_RC4_KEY_LENGTH + ) + { + // the field lengths are invalid ? This was not setup by initEncryption. + // do not encrypt after all + m_aContext.Encryption.OValue.clear(); + m_aContext.Encryption.UValue.clear(); + OSL_ENSURE( 0, "encryption data failed sanity check, encryption disabled" ); + } + else // setup key lengths + m_nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, m_nKeyLength, m_nRC4KeyLength ); + } + // write header OStringBuffer aBuffer( 20 ); aBuffer.append( "%PDF-" ); @@ -1811,139 +1830,138 @@ PDFWriterImpl::~PDFWriterImpl() rtl_freeMemory( m_pEncryptionBuffer ); } -void PDFWriterImpl::setDocInfo( const PDFDocInfo& rInfo ) +void PDFWriterImpl::setupDocInfo() { - m_aDocInfo.Title = rInfo.Title; - m_aDocInfo.Author = rInfo.Author; - m_aDocInfo.Subject = rInfo.Subject; - m_aDocInfo.Keywords = rInfo.Keywords; - m_aDocInfo.Creator = rInfo.Creator; - m_aDocInfo.Producer = rInfo.Producer; + std::vector< sal_uInt8 > aId; + computeDocumentIdentifier( aId, m_aContext.DocumentInfo, m_aCreationDateString, m_aCreationMetaDateString ); + if( m_aContext.Encryption.DocumentIdentifier.empty() ) + m_aContext.Encryption.DocumentIdentifier = aId; +} + +void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, + const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, + rtl::OString& o_rCString1, + rtl::OString& o_rCString2 + ) +{ + o_rIdentifier.clear(); -//build the document id + //build the document id rtl::OString aInfoValuesOut; OStringBuffer aID( 1024 ); - if( m_aDocInfo.Title.Len() ) - appendUnicodeTextString( m_aDocInfo.Title, aID ); - if( m_aDocInfo.Author.Len() ) - appendUnicodeTextString( m_aDocInfo.Author, aID ); - if( m_aDocInfo.Subject.Len() ) - appendUnicodeTextString( m_aDocInfo.Subject, aID ); - if( m_aDocInfo.Keywords.Len() ) - appendUnicodeTextString( m_aDocInfo.Keywords, aID ); - if( m_aDocInfo.Creator.Len() ) - appendUnicodeTextString( m_aDocInfo.Creator, aID ); - if( m_aDocInfo.Producer.Len() ) - appendUnicodeTextString( m_aDocInfo.Producer, aID ); + if( i_rDocInfo.Title.Len() ) + appendUnicodeTextString( i_rDocInfo.Title, aID ); + if( i_rDocInfo.Author.Len() ) + appendUnicodeTextString( i_rDocInfo.Author, aID ); + if( i_rDocInfo.Subject.Len() ) + appendUnicodeTextString( i_rDocInfo.Subject, aID ); + if( i_rDocInfo.Keywords.Len() ) + appendUnicodeTextString( i_rDocInfo.Keywords, aID ); + if( i_rDocInfo.Creator.Len() ) + appendUnicodeTextString( i_rDocInfo.Creator, aID ); + if( i_rDocInfo.Producer.Len() ) + appendUnicodeTextString( i_rDocInfo.Producer, aID ); TimeValue aTVal, aGMT; oslDateTime aDT; osl_getSystemTime( &aGMT ); osl_getLocalTimeFromSystemTime( &aGMT, &aTVal ); osl_getDateTimeFromTimeValue( &aTVal, &aDT ); - m_aCreationDateString.append( "D:" ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); -//--> i59651, we fill the Metadata date string as well, if PDF/A is requested - if( m_bIsPDF_A1 ) - { -// according to ISO 19005-1:2005 6.7.3 the date is corrected for -// local time zone offset UTC only, whereas Acrobat 8 seems -// to use the localtime notation only -// according to a raccomandation in XMP Specification (Jan 2004, page 75) -// the Acrobat way seems the right approach - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); - m_aCreationMetaDateString.append( "-" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); - m_aCreationMetaDateString.append( "-" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); - m_aCreationMetaDateString.append( "T" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); - m_aCreationMetaDateString.append( ":" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); - m_aCreationMetaDateString.append( ":" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); - } + rtl::OStringBuffer aCreationDateString(64), aCreationMetaDateString(64); + aCreationDateString.append( "D:" ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); + + //--> i59651, we fill the Metadata date string as well, if PDF/A is requested + // according to ISO 19005-1:2005 6.7.3 the date is corrected for + // local time zone offset UTC only, whereas Acrobat 8 seems + // to use the localtime notation only + // according to a raccomandation in XMP Specification (Jan 2004, page 75) + // the Acrobat way seems the right approach + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); + aCreationMetaDateString.append( "-" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); + aCreationMetaDateString.append( "-" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); + aCreationMetaDateString.append( "T" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); + aCreationMetaDateString.append( ":" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); + aCreationMetaDateString.append( ":" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); + sal_uInt32 nDelta = 0; if( aGMT.Seconds > aTVal.Seconds ) { - m_aCreationDateString.append( "-" ); + aCreationDateString.append( "-" ); nDelta = aGMT.Seconds-aTVal.Seconds; - if( m_bIsPDF_A1 ) - m_aCreationMetaDateString.append( "-" ); + aCreationMetaDateString.append( "-" ); } else if( aGMT.Seconds < aTVal.Seconds ) { - m_aCreationDateString.append( "+" ); + aCreationDateString.append( "+" ); nDelta = aTVal.Seconds-aGMT.Seconds; - if( m_bIsPDF_A1 ) - m_aCreationMetaDateString.append( "+" ); + aCreationMetaDateString.append( "+" ); } else { - m_aCreationDateString.append( "Z" ); - if( m_bIsPDF_A1 ) - m_aCreationMetaDateString.append( "Z" ); + aCreationDateString.append( "Z" ); + aCreationMetaDateString.append( "Z" ); } if( nDelta ) { - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); - m_aCreationDateString.append( "'" ); - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); - if( m_bIsPDF_A1 ) - { - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); - m_aCreationMetaDateString.append( ":" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); - } + aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); + aCreationDateString.append( "'" ); + aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); + aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); + + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); + aCreationMetaDateString.append( ":" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); } - m_aCreationDateString.append( "'" ); - aID.append( m_aCreationDateString.getStr(), m_aCreationDateString.getLength() ); + aCreationDateString.append( "'" ); + aID.append( aCreationDateString.getStr(), aCreationDateString.getLength() ); aInfoValuesOut = aID.makeStringAndClear(); + o_rCString1 = aCreationDateString.makeStringAndClear(); + o_rCString2 = aCreationMetaDateString.makeStringAndClear(); - DBG_ASSERT( m_aDigest != NULL, "PDFWrite_Impl::setDocInfo: cannot obtain a digest object !" ); - - m_aDocID.setLength( 0 ); - if( m_aDigest ) + rtlDigest aDigest = rtl_digest_createMD5(); + OSL_ENSURE( aDigest != NULL, "PDFWriterImpl::computeDocumentIdentifier: cannot obtain a digest object !" ); + if( aDigest ) { - osl_getSystemTime( &aGMT ); - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, &aGMT, sizeof( aGMT ) ); + rtlDigestError nError = rtl_digest_updateMD5( aDigest, &aGMT, sizeof( aGMT ) ); if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_aContext.URL.getStr(), m_aContext.URL.getLength()*sizeof(sal_Unicode) ); - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() ); + nError = rtl_digest_updateMD5( aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() ); if( nError == rtl_Digest_E_None ) { -//the binary form of the doc id is needed for encryption stuff - rtl_digest_getMD5( m_aDigest, m_nDocID, 16 ); - for( unsigned int i = 0; i < 16; i++ ) - appendHex( m_nDocID[i], m_aDocID ); + o_rIdentifier = std::vector< sal_uInt8 >( 16, 0 ); + //the binary form of the doc id is needed for encryption stuff + rtl_digest_getMD5( aDigest, &o_rIdentifier[0], 16 ); } } } @@ -1956,7 +1974,7 @@ append the string as unicode hex, encrypted if needed inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer ) { rOutBuffer.append( "<" ); - if( m_aContext.Encrypt ) + if( m_aContext.Encryption.Encrypt() ) { const sal_Unicode* pStr = rInString.getStr(); sal_Int32 nLen = rInString.getLength(); @@ -1993,7 +2011,7 @@ inline void PDFWriterImpl::appendLiteralStringEncrypt( rtl::OStringBuffer& rInSt rOutBuffer.append( "(" ); sal_Int32 nChars = rInString.getLength(); //check for encryption, if ok, encrypt the string, then convert with appndLiteralString - if( m_aContext.Encrypt && checkEncryptionBufferSize( nChars ) ) + if( m_aContext.Encryption.Encrypt() && checkEncryptionBufferSize( nChars ) ) { //encrypt the string in a buffer, then append it enableStringEncryption( nInObjectNumber ); @@ -2380,9 +2398,6 @@ SalLayout* PDFWriterImpl::GetTextLayout( ImplLayoutArgs& rArgs, ImplFontSelectDa sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation ) { - if( m_aContext.Encrypt && m_aPages.empty() ) - initEncryption(); - endPage(); m_nCurrentPage = m_aPages.size(); m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) ); @@ -5877,7 +5892,7 @@ bool PDFWriterImpl::emitCatalog() } // viewer preferences, if we had some, then emit if( m_aContext.HideViewerToolbar || - ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aDocInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) || + ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) || m_aContext.HideViewerMenubar || m_aContext.HideViewerWindowControls || m_aContext.FitWindow || m_aContext.CenterWindow || (m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) || @@ -5894,7 +5909,7 @@ bool PDFWriterImpl::emitCatalog() aLine.append( "/FitWindow true\n" ); if( m_aContext.CenterWindow ) aLine.append( "/CenterWindow true\n" ); - if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aDocInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) + if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) aLine.append( "/DisplayDocTitle true\n" ); if( m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) aLine.append( "/Direction/R2L\n" ); @@ -5998,40 +6013,40 @@ sal_Int32 PDFWriterImpl::emitInfoDict( ) aLine.append( nObject ); aLine.append( " 0 obj\n" "<<" ); - if( m_aDocInfo.Title.Len() ) + if( m_aContext.DocumentInfo.Title.Len() ) { aLine.append( "/Title" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Title, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Title, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Author.Len() ) + if( m_aContext.DocumentInfo.Author.Len() ) { aLine.append( "/Author" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Author, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Subject.Len() ) + if( m_aContext.DocumentInfo.Subject.Len() ) { aLine.append( "/Subject" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Subject, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Subject, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Keywords.Len() ) + if( m_aContext.DocumentInfo.Keywords.Len() ) { aLine.append( "/Keywords" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Keywords, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Keywords, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Creator.Len() ) + if( m_aContext.DocumentInfo.Creator.Len() ) { aLine.append( "/Creator" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Creator, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Creator, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Producer.Len() ) + if( m_aContext.DocumentInfo.Producer.Len() ) { aLine.append( "/Producer" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Producer, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Producer, nObject, aLine ); aLine.append( "\n" ); } @@ -6277,45 +6292,45 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata() aMetadataStream.append( " <pdfaid:conformance>A</pdfaid:conformance>\n" ); aMetadataStream.append( " </rdf:Description>\n" ); //... Dublin Core properties go here - if( m_aDocInfo.Title.Len() || - m_aDocInfo.Author.Len() || - m_aDocInfo.Subject.Len() ) + if( m_aContext.DocumentInfo.Title.Len() || + m_aContext.DocumentInfo.Author.Len() || + m_aContext.DocumentInfo.Subject.Len() ) { aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); aMetadataStream.append( " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" ); - if( m_aDocInfo.Title.Len() ) + if( m_aContext.DocumentInfo.Title.Len() ) { // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01) aMetadataStream.append( " <dc:title>\n" ); aMetadataStream.append( " <rdf:Alt>\n" ); aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" ); rtl::OUString aTitle; - escapeStringXML( m_aDocInfo.Title, aTitle ); + escapeStringXML( m_aContext.DocumentInfo.Title, aTitle ); aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</rdf:li>\n" ); aMetadataStream.append( " </rdf:Alt>\n" ); aMetadataStream.append( " </dc:title>\n" ); } - if( m_aDocInfo.Author.Len() ) + if( m_aContext.DocumentInfo.Author.Len() ) { aMetadataStream.append( " <dc:creator>\n" ); aMetadataStream.append( " <rdf:Seq>\n" ); aMetadataStream.append( " <rdf:li>" ); rtl::OUString aAuthor; - escapeStringXML( m_aDocInfo.Author, aAuthor ); + escapeStringXML( m_aContext.DocumentInfo.Author, aAuthor ); aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</rdf:li>\n" ); aMetadataStream.append( " </rdf:Seq>\n" ); aMetadataStream.append( " </dc:creator>\n" ); } - if( m_aDocInfo.Subject.Len() ) + if( m_aContext.DocumentInfo.Subject.Len() ) { // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01) aMetadataStream.append( " <dc:description>\n" ); aMetadataStream.append( " <rdf:Alt>\n" ); aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" ); rtl::OUString aSubject; - escapeStringXML( m_aDocInfo.Subject, aSubject ); + escapeStringXML( m_aContext.DocumentInfo.Subject, aSubject ); aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</rdf:li>\n" ); aMetadataStream.append( " </rdf:Alt>\n" ); @@ -6325,24 +6340,24 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata() } //... PDF properties go here - if( m_aDocInfo.Producer.Len() || - m_aDocInfo.Keywords.Len() ) + if( m_aContext.DocumentInfo.Producer.Len() || + m_aContext.DocumentInfo.Keywords.Len() ) { aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); aMetadataStream.append( " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" ); - if( m_aDocInfo.Producer.Len() ) + if( m_aContext.DocumentInfo.Producer.Len() ) { aMetadataStream.append( " <pdf:Producer>" ); rtl::OUString aProducer; - escapeStringXML( m_aDocInfo.Producer, aProducer ); + escapeStringXML( m_aContext.DocumentInfo.Producer, aProducer ); aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</pdf:Producer>\n" ); } - if( m_aDocInfo.Keywords.Len() ) + if( m_aContext.DocumentInfo.Keywords.Len() ) { aMetadataStream.append( " <pdf:Keywords>" ); rtl::OUString aKeywords; - escapeStringXML( m_aDocInfo.Keywords, aKeywords ); + escapeStringXML( m_aContext.DocumentInfo.Keywords, aKeywords ); aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</pdf:Keywords>\n" ); } @@ -6351,11 +6366,11 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata() aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); aMetadataStream.append( " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" ); - if( m_aDocInfo.Creator.Len() ) + if( m_aContext.DocumentInfo.Creator.Len() ) { aMetadataStream.append( " <xmp:CreatorTool>" ); rtl::OUString aCreator; - escapeStringXML( m_aDocInfo.Creator, aCreator ); + escapeStringXML( m_aContext.DocumentInfo.Creator, aCreator ); aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</xmp:CreatorTool>\n" ); } @@ -6411,7 +6426,7 @@ bool PDFWriterImpl::emitTrailer() sal_Int32 nSecObject = 0; - if( m_aContext.Encrypt == true ) + if( m_aContext.Encryption.Encrypt() ) { //emit the security information //must be emitted as indirect dictionary object, since @@ -6425,16 +6440,16 @@ bool PDFWriterImpl::emitTrailer() aLineS.append( " 0 obj\n" "<</Filter/Standard/V " ); // check the version - if( m_aContext.Security128bit == true ) + if( m_aContext.Encryption.Security128bit ) aLineS.append( "2/Length 128/R 3" ); else aLineS.append( "1/R 2" ); // emit the owner password, must not be encrypted aLineS.append( "/O(" ); - appendLiteralString( (const sal_Char*)m_nEncryptedOwnerPassword, 32, aLineS ); + appendLiteralString( (const sal_Char*)&m_aContext.Encryption.OValue[0], sal_Int32(m_aContext.Encryption.OValue.size()), aLineS ); aLineS.append( ")/U(" ); - appendLiteralString( (const sal_Char*)m_nEncryptedUserPassword, 32, aLineS ); + appendLiteralString( (const sal_Char*)&m_aContext.Encryption.UValue[0], sal_Int32(m_aContext.Encryption.UValue.size()), aLineS ); aLineS.append( ")/P " );// the permission set aLineS.append( m_nAccessPermissions ); aLineS.append( ">>\nendobj\n\n" ); @@ -6500,13 +6515,21 @@ bool PDFWriterImpl::emitTrailer() aLine.append( nDocInfoObject ); aLine.append( " 0 R\n" ); } - if( m_aDocID.getLength() ) + if( ! m_aContext.Encryption.DocumentIdentifier.empty() ) { aLine.append( "/ID [ <" ); - aLine.append( m_aDocID.getStr(), m_aDocID.getLength() ); + for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin(); + it != m_aContext.Encryption.DocumentIdentifier.end(); ++it ) + { + appendHex( sal_Int8(*it), aLine ); + } aLine.append( ">\n" "<" ); - aLine.append( m_aDocID.getStr(), m_aDocID.getLength() ); + for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin(); + it != m_aContext.Encryption.DocumentIdentifier.end(); ++it ) + { + appendHex( sal_Int8(*it), aLine ); + } aLine.append( "> ]\n" ); } if( aDocChecksum.getLength() ) @@ -9653,7 +9676,7 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) aLine.append( "[ /Indexed/DeviceRGB " ); aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) ); aLine.append( "\n<" ); - if( m_aContext.Encrypt ) + if( m_aContext.Encryption.Encrypt() ) { enableStringEncryption( rObject.m_nObject ); //check encryption buffer size @@ -12039,30 +12062,169 @@ void PDFWriterImpl::addStream( const String& rMimeType, PDFOutputStream* pStream } } + +sal_Bool PDFWriterImpl::checkEncryptionBufferSize( register sal_Int32 newSize ) +{ + if( m_nEncryptionBufferSize < newSize ) + { + /* reallocate the buffer, the used function allocate as rtl_allocateMemory + if the pointer parameter is NULL */ + m_pEncryptionBuffer = (sal_uInt8*)rtl_reallocateMemory( m_pEncryptionBuffer, newSize ); + if( m_pEncryptionBuffer ) + m_nEncryptionBufferSize = newSize; + else + m_nEncryptionBufferSize = 0; + } + return ( m_nEncryptionBufferSize != 0 ); +} + +void PDFWriterImpl::checkAndEnableStreamEncryption( register sal_Int32 nObject ) +{ + if( m_aContext.Encryption.Encrypt() ) + { + m_bEncryptThisStream = true; + sal_Int32 i = m_nKeyLength; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); + //the other location of m_nEncryptionKey are already set to 0, our fixed generation number + // do the MD5 hash + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + // the i+2 to take into account the generation number, always zero + rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) ); + // initialize the RC4 with the key + // key legth: see algoritm 3.1, step 4: (N+5) max 16 + rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); + } +} + +void PDFWriterImpl::enableStringEncryption( register sal_Int32 nObject ) +{ + if( m_aContext.Encryption.Encrypt() ) + { + sal_Int32 i = m_nKeyLength; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); + //the other location of m_nEncryptionKey are already set to 0, our fixed generation number + // do the MD5 hash + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + // the i+2 to take into account the generation number, always zero + rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) ); + // initialize the RC4 with the key + // key legth: see algoritm 3.1, step 4: (N+5) max 16 + rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); + } +} + +/* init the encryption engine +1. init the document id, used both for building the document id and for building the encryption key(s) +2. build the encryption key following algorithms described in the PDF specification + */ +bool PDFWriterImpl::initEncryption( vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + const vcl::PDFWriter::PDFDocInfo& i_rDocInfo + ) +{ + bool bSuccess = false; + rtl::OString aC1, aC2; + computeDocumentIdentifier( io_rProperties.DocumentIdentifier, i_rDocInfo, aC1, aC2 ); + if( i_rOwnerPassword.getLength() || i_rUserPassword.getLength() ) + { + sal_Int32 nKeyLength = 0, nRC4KeyLength = 0; + sal_Int32 nAccessPermissions = computeAccessPermissions( io_rProperties, nKeyLength, nRC4KeyLength ); + // get padded passwords + sal_uInt8 aPadUPW[ENCRYPTED_PWD_SIZE], aPadOPW[ENCRYPTED_PWD_SIZE]; + padPassword( i_rOwnerPassword.getLength() ? i_rOwnerPassword : i_rUserPassword, aPadOPW ); + padPassword( i_rUserPassword, aPadUPW ); + bSuccess = computeODictionaryValue( aPadOPW, aPadUPW, io_rProperties, nKeyLength, nRC4KeyLength ) + && computeUDictionaryValue( aPadOPW, aPadUPW, io_rProperties, nKeyLength, nRC4KeyLength, nAccessPermissions ) + ; + + // trash temporary padded cleartext PWDs + rtl_zeroMemory( aPadOPW, sizeof(aPadOPW) ); + rtl_zeroMemory( aPadUPW, sizeof(aPadUPW) ); + + //clear out exceding key values, prepares for generation number default to 0 as well + // see checkAndEnableStreamEncryption in pdfwriter_impl.hxx + if( bSuccess ) + { + sal_Int32 i, y; + for( i = nKeyLength, y = 0; y < 5 ; y++ ) + io_rProperties.EncryptionKey[i++] = 0; + } + } + else + bSuccess = true; + + if( ! bSuccess ) // something failed, disable encrpytion + { + io_rProperties.OValue.clear(); + io_rProperties.UValue.clear(); + io_rProperties.EncryptionKey.clear(); + } + + return bSuccess; +} + +sal_Int32 PDFWriterImpl::computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties, + sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength ) +{ + /* + 2) compute the access permissions, in numerical form + + the default value depends on the revision 2 (40 bit) or 3 (128 bit security): + - for 40 bit security the unused bit must be set to 1, since they are not used + - for 128 bit security the same bit must be preset to 0 and set later if needed + according to the table 3.15, pdf v 1.4 */ + sal_Int32 nAccessPermissions = ( i_rProperties.Security128bit ) ? 0xfffff0c0 : 0xffffffc0 ; + + /* check permissions for 40 bit security case */ + nAccessPermissions |= ( i_rProperties.CanPrintTheDocument ) ? 1 << 2 : 0; + nAccessPermissions |= ( i_rProperties.CanModifyTheContent ) ? 1 << 3 : 0; + nAccessPermissions |= ( i_rProperties.CanCopyOrExtract ) ? 1 << 4 : 0; + nAccessPermissions |= ( i_rProperties.CanAddOrModify ) ? 1 << 5 : 0; + o_rKeyLength = SECUR_40BIT_KEY; + o_rRC4KeyLength = SECUR_40BIT_KEY+5; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 5 + + if( i_rProperties.Security128bit ) + { + o_rKeyLength = SECUR_128BIT_KEY; + o_rRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16, thus maximum + // permitted value is 16 + nAccessPermissions |= ( i_rProperties.CanFillInteractive ) ? 1 << 8 : 0; + nAccessPermissions |= ( i_rProperties.CanExtractForAccessibility ) ? 1 << 9 : 0; + nAccessPermissions |= ( i_rProperties.CanAssemble ) ? 1 << 10 : 0; + nAccessPermissions |= ( i_rProperties.CanPrintFull ) ? 1 << 11 : 0; + } + return nAccessPermissions; +} + /************************************************************* begin i12626 methods Implements Algorithm 3.2, step 1 only */ -void PDFWriterImpl::padPassword( rtl::OUString aPassword, sal_uInt8 *paPasswordTarget ) +void PDFWriterImpl::padPassword( const rtl::OUString& i_rPassword, sal_uInt8* o_pPaddedPW ) { -// get ansi-1252 version of the password string CHECKIT ! i12626 - rtl::OString aString = rtl::OUStringToOString( aPassword, RTL_TEXTENCODING_MS_1252 ); + // get ansi-1252 version of the password string CHECKIT ! i12626 + rtl::OString aString( rtl::OUStringToOString( i_rPassword, RTL_TEXTENCODING_MS_1252 ) ); -//copy the string to the target - sal_Int32 nToCopy = ( aString.getLength() < 32 ) ? aString.getLength() : 32; + //copy the string to the target + sal_Int32 nToCopy = ( aString.getLength() < ENCRYPTED_PWD_SIZE ) ? aString.getLength() : ENCRYPTED_PWD_SIZE; sal_Int32 nCurrentChar; for( nCurrentChar = 0; nCurrentChar < nToCopy; nCurrentChar++ ) - paPasswordTarget[nCurrentChar] = (sal_uInt8)( aString.getStr()[nCurrentChar] ); + o_pPaddedPW[nCurrentChar] = (sal_uInt8)( aString.getStr()[nCurrentChar] ); -//pad it - if( nCurrentChar < 32 ) - {//fill with standard byte string - sal_Int32 i,y; - for( i = nCurrentChar, y = 0 ; i < 32; i++, y++ ) - paPasswordTarget[i] = m_nPadString[y]; - } + //pad it with standard byte string + sal_Int32 i,y; + for( i = nCurrentChar, y = 0 ; i < ENCRYPTED_PWD_SIZE; i++, y++ ) + o_pPaddedPW[i] = s_nPadString[y]; + + // trash memory of temporary clear text password + rtl_zeroMemory( (sal_Char*)aString.getStr(), aString.getLength() ); } /********************************** @@ -12075,91 +12237,126 @@ it will be 16 byte long for 128 bit security; for 40 bit security only the first TODO: in pdf ver 1.5 and 1.6 the step 6 is different, should be implemented. See spec. */ -void PDFWriterImpl::computeEncryptionKey(sal_uInt8 *paThePaddedPassword, sal_uInt8 *paEncryptionKey ) +bool PDFWriterImpl::computeEncryptionKey( const sal_uInt8* i_pOPW, const sal_uInt8* i_pUPW, vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, sal_Int32 i_nAccessPermissions ) { -//step 2 - if( m_aDigest ) + bool bSuccess = true; + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + + rtlDigest aDigest = rtl_digest_createMD5(); + if( aDigest ) { - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, paThePaddedPassword, ENCRYPTED_PWD_SIZE ); -//step 3 - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_nEncryptedOwnerPassword , sizeof( m_nEncryptedOwnerPassword ) ); -//Step 4 + //step 2 + rtlDigestError nError = rtl_digest_updateMD5( aDigest, i_pUPW, ENCRYPTED_PWD_SIZE ); + //step 3 + if( nError == rtl_Digest_E_None && ! io_rProperties.OValue.empty() ) + nError = rtl_digest_updateMD5( aDigest, &io_rProperties.OValue[0] , sal_Int32(io_rProperties.OValue.size()) ); + else + bSuccess = false; + //Step 4 sal_uInt8 nPerm[4]; - nPerm[0] = (sal_uInt8)m_nAccessPermissions; - nPerm[1] = (sal_uInt8)( m_nAccessPermissions >> 8 ); - nPerm[2] = (sal_uInt8)( m_nAccessPermissions >> 16 ); - nPerm[3] = (sal_uInt8)( m_nAccessPermissions >> 24 ); + nPerm[0] = (sal_uInt8)i_nAccessPermissions; + nPerm[1] = (sal_uInt8)( i_nAccessPermissions >> 8 ); + nPerm[2] = (sal_uInt8)( i_nAccessPermissions >> 16 ); + nPerm[3] = (sal_uInt8)( i_nAccessPermissions >> 24 ); if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, nPerm , sizeof( nPerm ) ); + nError = rtl_digest_updateMD5( aDigest, nPerm , sizeof( nPerm ) ); -//step 5, get the document ID, binary form + //step 5, get the document ID, binary form if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_nDocID , sizeof( m_nDocID ) ); -//get the digest - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) ); + //get the digest if( nError == rtl_Digest_E_None ) { - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); -//step 6, only if 128 bit - if( m_aContext.Security128bit ) + //step 6, only if 128 bit + if( io_rProperties.Security128bit ) { for( sal_Int32 i = 0; i < 50; i++ ) { - nError = rtl_digest_updateMD5( m_aDigest, &nMD5Sum, sizeof( nMD5Sum ) ); + nError = rtl_digest_updateMD5( aDigest, &nMD5Sum, sizeof( nMD5Sum ) ); if( nError != rtl_Digest_E_None ) + { + bSuccess = false; break; - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + } + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); } } } -//Step 7 + rtl_digest_destroyMD5( aDigest ); + } + else + bSuccess = false; + + //Step 7 + if( bSuccess ) + { + io_rProperties.EncryptionKey.resize( MAXIMUM_RC4_KEY_LENGTH ); for( sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++ ) - paEncryptionKey[i] = nMD5Sum[i]; + io_rProperties.EncryptionKey[i] = nMD5Sum[i]; } + else + io_rProperties.EncryptionKey.clear(); + + return bSuccess; } /********************************** Algorithm 3.3 Compute the encryption dictionary /O value, save into the class data member the step numbers down here correspond to the ones in PDF v.1.4 specfication */ -void PDFWriterImpl::computeODictionaryValue() +bool PDFWriterImpl::computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, + const sal_uInt8* i_pPaddedUserPassword, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nKeyLength, + sal_Int32 i_nRC4KeyLength + ) { -//step 1 already done, data is in m_nPaddedOwnerPassword -//step 2 - if( m_aDigest ) + bool bSuccess = true; + + io_rProperties.OValue.resize( ENCRYPTED_PWD_SIZE ); + + rtlDigest aDigest = rtl_digest_createMD5(); + rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); + if( aDigest && aCipher) { - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, &m_nPaddedOwnerPassword, sizeof( m_nPaddedOwnerPassword ) ); + //step 1 already done, data is in i_pPaddedOwnerPassword + //step 2 + + rtlDigestError nError = rtl_digest_updateMD5( aDigest, i_pPaddedOwnerPassword, ENCRYPTED_PWD_SIZE ); if( nError == rtl_Digest_E_None ) { sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof(nMD5Sum) ); + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) ); //step 3, only if 128 bit - if( m_aContext.Security128bit ) + if( io_rProperties.Security128bit ) { sal_Int32 i; for( i = 0; i < 50; i++ ) { - nError = rtl_digest_updateMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + nError = rtl_digest_updateMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); if( nError != rtl_Digest_E_None ) + { + bSuccess = false; break; - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + } + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); } } -//Step 4, the key is in nMD5Sum -//step 5 already done, data is in m_nPaddedUserPassword -//step 6 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - nMD5Sum, m_nKeyLength , NULL, 0 ); -// encrypt the user password using the key set above - rtl_cipher_encodeARCFOUR( m_aCipher, m_nPaddedUserPassword, sizeof( m_nPaddedUserPassword ), // the data to be encrypted - m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ) ); //encrypted data, stored in class data member -//Step 7, only if 128 bit - if( m_aContext.Security128bit ) + //Step 4, the key is in nMD5Sum + //step 5 already done, data is in i_pPaddedUserPassword + //step 6 + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + nMD5Sum, i_nKeyLength , NULL, 0 ); + // encrypt the user password using the key set above + rtl_cipher_encodeARCFOUR( aCipher, i_pPaddedUserPassword, ENCRYPTED_PWD_SIZE, // the data to be encrypted + &io_rProperties.OValue[0], sal_Int32(io_rProperties.OValue.size()) ); //encrypted data + //Step 7, only if 128 bit + if( io_rProperties.Security128bit ) { sal_uInt32 i, y; sal_uInt8 nLocalKey[ SECUR_128BIT_KEY ]; // 16 = 128 bit key @@ -12169,138 +12366,116 @@ void PDFWriterImpl::computeODictionaryValue() for( y = 0; y < sizeof( nLocalKey ); y++ ) nLocalKey[y] = (sal_uInt8)( nMD5Sum[y] ^ i ); - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, nLocalKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area, on init can be NULL - rtl_cipher_encodeARCFOUR( m_aCipher, m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ), // the data to be encrypted - m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ) ); // encrypted data, can be the same as the input, encrypt "in place" -//step 8, store in class data member + rtl_cipher_encodeARCFOUR( aCipher, &io_rProperties.OValue[0], sal_Int32(io_rProperties.OValue.size()), // the data to be encrypted + &io_rProperties.OValue[0], sal_Int32(io_rProperties.OValue.size()) ); // encrypted data, can be the same as the input, encrypt "in place" + //step 8, store in class data member } } } + else + bSuccess = false; } + else + bSuccess = false; + + if( aDigest ) + rtl_digest_destroyMD5( aDigest ); + if( aCipher ) + rtl_cipher_destroyARCFOUR( aCipher ); + + if( ! bSuccess ) + io_rProperties.OValue.clear(); + return bSuccess; } /********************************** Algorithms 3.4 and 3.5 Compute the encryption dictionary /U value, save into the class data member, revision 2 (40 bit) or 3 (128 bit) */ -void PDFWriterImpl::computeUDictionaryValue() +bool PDFWriterImpl::computeUDictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, + const sal_uInt8* i_pPaddedUserPassword, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nKeyLength, + sal_Int32 i_nRC4KeyLength, + sal_Int32 i_nAccessPermissions + ) { -//step 1, common to both 3.4 and 3.5 - computeEncryptionKey( m_nPaddedUserPassword , m_nEncryptionKey ); + bool bSuccess = true; - if( m_aContext.Security128bit == false ) - { -//3.4 -//step 2 and 3 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - m_nEncryptionKey, 5 , // key and key length - NULL, 0 ); //destination data area -// encrypt the user password using the key set above, save for later use - rtl_cipher_encodeARCFOUR( m_aCipher, m_nPadString, sizeof( m_nPadString ), // the data to be encrypted - m_nEncryptedUserPassword, sizeof( m_nEncryptedUserPassword ) ); //encrypted data, stored in class data member - } - else + io_rProperties.UValue.resize( ENCRYPTED_PWD_SIZE ); + + rtlDigest aDigest = rtl_digest_createMD5(); + rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); + if( aDigest && aCipher ) { -//or 3.5, for 128 bit security -//step6, initilize the last 16 bytes of the encrypted user password to 0 - for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sizeof( m_nEncryptedUserPassword ); i++) - m_nEncryptedUserPassword[i] = 0; -//step 2 - if( m_aDigest ) + //step 1, common to both 3.4 and 3.5 + if( computeEncryptionKey( i_pPaddedOwnerPassword, i_pPaddedUserPassword, io_rProperties, i_nAccessPermissions ) ) { - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, m_nPadString, sizeof( m_nPadString ) ); -//step 3 - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_nDocID , sizeof(m_nDocID) ); - - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof(nMD5Sum) ); -//Step 4 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - m_nEncryptionKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area - rtl_cipher_encodeARCFOUR( m_aCipher, nMD5Sum, sizeof( nMD5Sum ), // the data to be encrypted - m_nEncryptedUserPassword, sizeof( nMD5Sum ) ); //encrypted data, stored in class data member -//step 5 - sal_uInt32 i, y; - sal_uInt8 nLocalKey[SECUR_128BIT_KEY]; - - for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 + if( io_rProperties.Security128bit == false ) + { + //3.4 + //step 2 and 3 + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + &io_rProperties.EncryptionKey[0], 5 , // key and key length + NULL, 0 ); //destination data area + // encrypt the user password using the key set above, save for later use + rtl_cipher_encodeARCFOUR( aCipher, s_nPadString, sizeof( s_nPadString ), // the data to be encrypted + &io_rProperties.UValue[0], sal_Int32(io_rProperties.UValue.size()) ); //encrypted data, stored in class data member + } + else { - for( y = 0; y < sizeof( nLocalKey ) ; y++ ) - nLocalKey[y] = (sal_uInt8)( m_nEncryptionKey[y] ^ i ); - - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - nLocalKey, SECUR_128BIT_KEY, // key and key length - NULL, 0 ); //destination data area, on init can be NULL - rtl_cipher_encodeARCFOUR( m_aCipher, m_nEncryptedUserPassword, SECUR_128BIT_KEY, // the data to be encrypted - m_nEncryptedUserPassword, SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place" + //or 3.5, for 128 bit security + //step6, initilize the last 16 bytes of the encrypted user password to 0 + for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sal_uInt32(io_rProperties.UValue.size()); i++) + io_rProperties.UValue[i] = 0; + //step 2 + rtlDigestError nError = rtl_digest_updateMD5( aDigest, s_nPadString, sizeof( s_nPadString ) ); + //step 3 + if( nError == rtl_Digest_E_None ) + nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) ); + else + bSuccess = false; + + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) ); + //Step 4 + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + &io_rProperties.EncryptionKey[0], SECUR_128BIT_KEY, NULL, 0 ); //destination data area + rtl_cipher_encodeARCFOUR( aCipher, nMD5Sum, sizeof( nMD5Sum ), // the data to be encrypted + &io_rProperties.UValue[0], sizeof( nMD5Sum ) ); //encrypted data, stored in class data member + //step 5 + sal_uInt32 i, y; + sal_uInt8 nLocalKey[SECUR_128BIT_KEY]; + + for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 + { + for( y = 0; y < sizeof( nLocalKey ) ; y++ ) + nLocalKey[y] = (sal_uInt8)( io_rProperties.EncryptionKey[y] ^ i ); + + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + nLocalKey, SECUR_128BIT_KEY, // key and key length + NULL, 0 ); //destination data area, on init can be NULL + rtl_cipher_encodeARCFOUR( aCipher, &io_rProperties.UValue[0], SECUR_128BIT_KEY, // the data to be encrypted + &io_rProperties.UValue[0], SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place" + } } } + else + bSuccess = false; } -} - -/* init the encryption engine -1. init the document id, used both for building the document id and for building the encryption key(s) -2. build the encryption key following algorithms described in the PDF specification - */ -void PDFWriterImpl::initEncryption() -{ - m_aOwnerPassword = m_aContext.OwnerPassword; - m_aUserPassword = m_aContext.UserPassword; -/* password stuff computing, before sending out anything */ - DBG_ASSERT( m_aCipher != NULL, "PDFWriterImpl::initEncryption: a cipher (ARCFOUR) object is not available !" ); - DBG_ASSERT( m_aDigest != NULL, "PDFWriterImpl::initEncryption: a digest (MD5) object is not available !" ); + else + bSuccess = false; - if( m_aCipher && m_aDigest ) - { -//if there is no owner password, force it to the user password - if( m_aOwnerPassword.getLength() == 0 ) - m_aOwnerPassword = m_aUserPassword; + if( aDigest ) + rtl_digest_destroyMD5( aDigest ); + if( aCipher ) + rtl_cipher_destroyARCFOUR( aCipher ); - initPadString(); -/* -1) pad passwords -*/ - padPassword( m_aOwnerPassword, m_nPaddedOwnerPassword ); - padPassword( m_aUserPassword, m_nPaddedUserPassword ); -/* -2) compute the access permissions, in numerical form - -the default value depends on the revision 2 (40 bit) or 3 (128 bit security): -- for 40 bit security the unused bit must be set to 1, since they are not used -- for 128 bit security the same bit must be preset to 0 and set later if needed -according to the table 3.15, pdf v 1.4 */ - m_nAccessPermissions = ( m_aContext.Security128bit ) ? 0xfffff0c0 : 0xffffffc0 ; - -/* check permissions for 40 bit security case */ - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanPrintTheDocument ) ? 1 << 2 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanModifyTheContent ) ? 1 << 3 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanCopyOrExtract ) ? 1 << 4 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanAddOrModify ) ? 1 << 5 : 0; - m_nKeyLength = SECUR_40BIT_KEY; - m_nRC4KeyLength = SECUR_40BIT_KEY+5; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 5 - - if( m_aContext.Security128bit ) - { - m_nKeyLength = SECUR_128BIT_KEY; - m_nRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16, thus maximum - // permitted value is 16 - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanFillInteractive ) ? 1 << 8 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanExtractForAccessibility ) ? 1 << 9 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanAssemble ) ? 1 << 10 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanPrintFull ) ? 1 << 11 : 0; - } - computeODictionaryValue(); - computeUDictionaryValue(); - -//clear out exceding key values, prepares for generation number default to 0 as well -// see checkAndEnableStreamEncryption in pdfwriter_impl.hxx - sal_Int32 i, y; - for( i = m_nKeyLength, y = 0; y < 5 ; y++ ) - m_nEncryptionKey[i++] = 0; - } - else //either no cipher or no digest or both, something is wrong with memory or something else - m_aContext.Encrypt = false; //then turn the encryption off + if( ! bSuccess ) + io_rProperties.UValue.clear(); + return bSuccess; } + /* end i12626 methods */ diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index 2eacdc215dd8..dd75ca4f1a47 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -595,7 +595,6 @@ private: MapMode m_aMapMode; // PDFWriterImpl scaled units std::vector< PDFPage > m_aPages; - PDFDocInfo m_aDocInfo; /* maps object numbers to file offsets (needed for xref) */ std::vector< sal_uInt64 > m_aObjects; /* contains Bitmaps until they are written to the @@ -796,116 +795,37 @@ i12626 /* used to cipher the stream data and for password management */ rtlCipher m_aCipher; rtlDigest m_aDigest; -/* pad string used for password in Standard security handler */ - sal_uInt8 m_nPadString[ENCRYPTED_PWD_SIZE]; -/* the owner password, in clear text */ - rtl::OUString m_aOwnerPassword; -/* the padded owner password */ - sal_uInt8 m_nPaddedOwnerPassword[ENCRYPTED_PWD_SIZE]; -/* the encryption dictionary owner password, according to algorithm 3.3 */ - sal_uInt8 m_nEncryptedOwnerPassword[ENCRYPTED_PWD_SIZE]; -/* the user password, in clear text */ - rtl::OUString m_aUserPassword; -/* the padded user password */ - sal_uInt8 m_nPaddedUserPassword[ENCRYPTED_PWD_SIZE]; -/* the encryption dictionary user password, according to algorithm 3.4 or 3.5 depending on the - security handler revision */ - sal_uInt8 m_nEncryptedUserPassword[ENCRYPTED_PWD_SIZE]; - -/* the encryption key, formed with the user password according to algorithm 3.2, maximum length is 16 bytes + 3 + 2 - for 128 bit security */ - sal_uInt8 m_nEncryptionKey[MAXIMUM_RC4_KEY_LENGTH]; + /* pad string used for password in Standard security handler */ + static const sal_uInt8 s_nPadString[ENCRYPTED_PWD_SIZE]; + + /* the encryption key, formed with the user password according to algorithm 3.2, maximum length is 16 bytes + 3 + 2 + for 128 bit security */ sal_Int32 m_nKeyLength; // key length, 16 or 5 sal_Int32 m_nRC4KeyLength; // key length, 16 or 10, to be input to the algorith 3.1 -/* set to true if the following stream must be encrypted, used inside writeBuffer() */ + /* set to true if the following stream must be encrypted, used inside writeBuffer() */ sal_Bool m_bEncryptThisStream; -/* the numerical value of the access permissions, according to PDF spec, must be signed */ + /* the numerical value of the access permissions, according to PDF spec, must be signed */ sal_Int32 m_nAccessPermissions; -/* the document ID, the raw MD5 hash */ - sal_uInt8 m_nDocID[MD5_DIGEST_SIZE]; -/* string buffer to hold document ID, this is the output string */ - rtl::OStringBuffer m_aDocID; -/* string to hold the PDF creation date */ - rtl::OStringBuffer m_aCreationDateString; -/* string to hold the PDF creation date, for PDF/A metadata */ - rtl::OStringBuffer m_aCreationMetaDateString; -/* the buffer where the data are encrypted, dynamically allocated */ + /* string to hold the PDF creation date */ + rtl::OString m_aCreationDateString; + /* string to hold the PDF creation date, for PDF/A metadata */ + rtl::OString m_aCreationMetaDateString; + /* the buffer where the data are encrypted, dynamically allocated */ sal_uInt8 *m_pEncryptionBuffer; -/* size of the buffer */ + /* size of the buffer */ sal_Int32 m_nEncryptionBufferSize; -/* check and reallocate the buffer for encryption */ - sal_Bool checkEncryptionBufferSize( register sal_Int32 newSize ) - { - if( m_nEncryptionBufferSize < newSize ) - { -/* reallocate the buffer, the used function allocate as rtl_allocateMemory - if the pointer parameter is NULL */ - m_pEncryptionBuffer = (sal_uInt8*)rtl_reallocateMemory( m_pEncryptionBuffer, newSize ); - if( m_pEncryptionBuffer ) - m_nEncryptionBufferSize = newSize; - else - m_nEncryptionBufferSize = 0; - } - return ( m_nEncryptionBufferSize != 0 ); - } -/* init the internal pad string */ - void initPadString() - { - static const sal_uInt8 nPadString[32] = - { - 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, - 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A - }; - - for(sal_uInt32 i = 0; i < sizeof( nPadString ); i++ ) - m_nPadString[i] = nPadString[i]; - - }; -/* initialize the encryption engine */ - void initEncryption(); - -/* this function implements part of the PDF spec algorithm 3.1 in encryption, the rest (the actual encryption) is in PDFWriterImpl::writeBuffer */ - void checkAndEnableStreamEncryption( register sal_Int32 nObject ) - { - if( m_aContext.Encrypt ) - { - m_bEncryptThisStream = true; - register sal_Int32 i = m_nKeyLength; - m_nEncryptionKey[i++] = (sal_uInt8)nObject; - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); -//the other location of m_nEncryptionKey are already set to 0, our fixed generation number -// do the MD5 hash - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - // the i+2 to take into account the generation number, always zero - rtl_digest_MD5( &m_nEncryptionKey, i+2, nMD5Sum, sizeof(nMD5Sum) ); -// initialize the RC4 with the key -// key legth: see algoritm 3.1, step 4: (N+5) max 16 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); - } - }; + /* check and reallocate the buffer for encryption */ + sal_Bool checkEncryptionBufferSize( register sal_Int32 newSize ); + /* this function implements part of the PDF spec algorithm 3.1 in encryption, the rest (the actual encryption) is in PDFWriterImpl::writeBuffer */ + void checkAndEnableStreamEncryption( register sal_Int32 nObject ); void disableStreamEncryption() { m_bEncryptThisStream = false; }; -/* */ - void enableStringEncryption( register sal_Int32 nObject ) - { - register sal_Int32 i = m_nKeyLength; - m_nEncryptionKey[i++] = (sal_uInt8)nObject; - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); -//the other location of m_nEncryptionKey are already set to 0, our fixed generation number -// do the MD5 hash - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - // the i+2 to take into account the generation number, always zero - rtl_digest_MD5( &m_nEncryptionKey, i+2, nMD5Sum, sizeof(nMD5Sum) ); -// initialize the RC4 with the key -// key legth: see algoritm 3.1, step 4: (N+5) max 16 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); - }; + /* */ + void enableStringEncryption( register sal_Int32 nObject ); // test if the encryption is active, if yes than encrypt the unicode string and add to the OStringBuffer parameter void appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ); @@ -1096,23 +1016,47 @@ i12626 /* true if PDF/A-1a or PDF/A-1b is output */ sal_Bool m_bIsPDF_A1; -/* -i12626 -methods for PDF security - - pad a password according algorithm 3.2, step 1 */ - void padPassword( const rtl::OUString aPassword, sal_uInt8 *paPasswordTarget ); -/* algorithm 3.2: compute an encryption key */ - void computeEncryptionKey( sal_uInt8 *paThePaddedPassword, sal_uInt8 *paEncryptionKey ); -/* algorithm 3.3: computing the encryption dictionary'ss owner password value ( /O ) */ - void computeODictionaryValue(); -/* algorithm 3.4 or 3.5: computing the encryption dictionary's user password value ( /U ) revision 2 or 3 of the standard security handler */ - void computeUDictionaryValue(); - + /* + i12626 + methods for PDF security + + pad a password according algorithm 3.2, step 1 */ + static void padPassword( const rtl::OUString& i_rPassword, sal_uInt8* o_pPaddedPW ); + /* algorithm 3.2: compute an encryption key */ + static bool computeEncryptionKey( const sal_uInt8* i_pOPW, const sal_uInt8* i_pUPW, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nAccessPermissions + ); + /* algorithm 3.3: computing the encryption dictionary'ss owner password value ( /O ) */ + static bool computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, const sal_uInt8* i_pPaddedUserPassword, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nKeyLength, sal_Int32 i_nRC4KeyLength + ); + /* algorithm 3.4 or 3.5: computing the encryption dictionary's user password value ( /U ) revision 2 or 3 of the standard security handler */ + static bool computeUDictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, const sal_uInt8* i_pPaddedUserPassword, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nKeyLength, sal_Int32 i_nRC4KeyLength, + sal_Int32 i_nAccessPermissions + ); + + static void computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, + const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, + rtl::OString& o_rCString1, + rtl::OString& o_rCString2 + ); + static sal_Int32 computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties, + sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength ); + void setupDocInfo(); public: PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext ); ~PDFWriterImpl(); + static bool initEncryption( vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + const vcl::PDFWriter::PDFDocInfo& i_rDocInfo + ); + /* for OutputDevice so the reference device can have a list * that contains only suitable fonts (subsettable or builtin) * produces a new font list @@ -1144,8 +1088,6 @@ public: } PDFWriter::PDFVersion getVersion() const { return m_aContext.Version; } - void setDocInfo( const PDFDocInfo& rInfo ); - const PDFDocInfo& getDocInfo() const { return m_aDocInfo; } void setDocumentLocale( const com::sun::star::lang::Locale& rLoc ) { m_aContext.DocumentLocale = rLoc; } |