summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorPhilipp Lohmann [pl] <Philipp.Lohmann@Oracle.COM>2010-09-24 14:28:04 +0200
committerPhilipp Lohmann [pl] <Philipp.Lohmann@Oracle.COM>2010-09-24 14:28:04 +0200
commit4d25643942f30ad94b853a65338098d842767ed8 (patch)
tree7d19291fc57940703b55a3a0ffba133849d10fe0 /vcl
parenta555527edb34036835b167f0b3b7f6d515f098c4 (diff)
step1: put encrpytion parameters into PDFContext
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/vcl/pdfwriter.hxx82
-rw-r--r--vcl/source/gdi/pdfwriter.cxx20
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx817
-rw-r--r--vcl/source/gdi/pdfwriter_impl.hxx170
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; }