~ubuntu-branches/ubuntu/trusty/pdfmod/trusty

« back to all changes in this revision

Viewing changes to lib/PdfSharp/PdfSharp.Pdf.Security/PdfStandardSecurityHandler.cs

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2010-06-18 03:44:46 UTC
  • Revision ID: james.westby@ubuntu.com-20100618034446-bogifrsscpayp361
Tags: upstream-0.8.3
Import upstream version 0.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#region PDFsharp - A .NET library for processing PDF
 
2
//
 
3
// Authors:
 
4
//   Stefan Lange (mailto:Stefan.Lange@pdfsharp.com)
 
5
//
 
6
// Copyright (c) 2005-2008 empira Software GmbH, Cologne (Germany)
 
7
//
 
8
// http://www.pdfsharp.com
 
9
// http://sourceforge.net/projects/pdfsharp
 
10
//
 
11
// Permission is hereby granted, free of charge, to any person obtaining a
 
12
// copy of this software and associated documentation files (the "Software"),
 
13
// to deal in the Software without restriction, including without limitation
 
14
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
15
// and/or sell copies of the Software, and to permit persons to whom the
 
16
// Software is furnished to do so, subject to the following conditions:
 
17
//
 
18
// The above copyright notice and this permission notice shall be included
 
19
// in all copies or substantial portions of the Software.
 
20
//
 
21
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
22
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
23
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 
24
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
25
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
26
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 
27
// DEALINGS IN THE SOFTWARE.
 
28
#endregion
 
29
 
 
30
using System;
 
31
using System.Diagnostics;
 
32
using System.Collections;
 
33
using PdfSharp.Drawing;
 
34
using PdfSharp.Internal;
 
35
using PdfSharp.Pdf;
 
36
using PdfSharp.Pdf.IO;
 
37
using PdfSharp.Pdf.Advanced;
 
38
using PdfSharp.Pdf.Internal;
 
39
using System.Security.Cryptography;
 
40
 
 
41
namespace PdfSharp.Pdf.Security
 
42
{
 
43
  /// <summary>
 
44
  /// Represents the standard PDF security handler.
 
45
  /// </summary>
 
46
  public sealed class PdfStandardSecurityHandler : PdfSecurityHandler
 
47
  {
 
48
    internal PdfStandardSecurityHandler(PdfDocument document)
 
49
      : base(document)
 
50
    {
 
51
    }
 
52
 
 
53
    internal PdfStandardSecurityHandler(PdfDictionary dict)
 
54
      : base(dict)
 
55
    {
 
56
    }
 
57
 
 
58
    /// <summary>
 
59
    /// Sets the user password of the document. Setting a password automatically sets the
 
60
    /// PdfDocumentSecurityLevel to PdfDocumentSecurityLevel.Encrypted128Bit if its current
 
61
    /// value is PdfDocumentSecurityLevel.None.
 
62
    /// </summary>
 
63
    public string UserPassword
 
64
    {
 
65
      set
 
66
      {
 
67
        if (this.document.securitySettings.DocumentSecurityLevel == PdfDocumentSecurityLevel.None)
 
68
          this.document.securitySettings.DocumentSecurityLevel = PdfDocumentSecurityLevel.Encrypted128Bit;
 
69
        this.userPassword = value;
 
70
      }
 
71
    }
 
72
    internal string userPassword;
 
73
 
 
74
    /// <summary>
 
75
    /// Sets the owner password of the document. Setting a password automatically sets the
 
76
    /// PdfDocumentSecurityLevel to PdfDocumentSecurityLevel.Encrypted128Bit if its current
 
77
    /// value is PdfDocumentSecurityLevel.None.
 
78
    /// </summary>
 
79
    public string OwnerPassword
 
80
    {
 
81
      set
 
82
      {
 
83
        if (this.document.securitySettings.DocumentSecurityLevel == PdfDocumentSecurityLevel.None)
 
84
          this.document.securitySettings.DocumentSecurityLevel = PdfDocumentSecurityLevel.Encrypted128Bit;
 
85
        this.ownerPassword = value;
 
86
      }
 
87
    }
 
88
    internal string ownerPassword;
 
89
 
 
90
    /// <summary>
 
91
    /// Gets or sets the user access permission represented as an integer in the P key.
 
92
    /// </summary>
 
93
    internal PdfUserAccessPermission Permission
 
94
    {
 
95
      get
 
96
      {
 
97
        PdfUserAccessPermission permission = (PdfUserAccessPermission)Elements.GetInteger(Keys.P);
 
98
        if ((int)permission == 0)
 
99
          permission = PdfUserAccessPermission.PermitAll;
 
100
        return permission;
 
101
      }
 
102
      set { Elements.SetInteger(Keys.P, (int)value); }
 
103
    }
 
104
 
 
105
    /// <summary>
 
106
    /// Encrypts the whole document.
 
107
    /// </summary>
 
108
    public void EncryptDocument()
 
109
    {
 
110
      foreach (PdfReference iref in this.document.irefTable.AllReferences)
 
111
      {
 
112
        if (!Object.ReferenceEquals(iref.Value, this))
 
113
          EncryptObject(iref.Value);
 
114
      }
 
115
    }
 
116
 
 
117
    /// <summary>
 
118
    /// Encrypts an indirect object.
 
119
    /// </summary>
 
120
    internal void EncryptObject(PdfObject value)
 
121
    {
 
122
      Debug.Assert(value.Reference != null);
 
123
 
 
124
      SetHashKey(value.ObjectID);
 
125
#if DEBUG
 
126
      if (value.ObjectID.ObjectNumber == 10)
 
127
        GetType();
 
128
#endif
 
129
 
 
130
      PdfDictionary dict;
 
131
      PdfArray array;
 
132
      PdfStringObject str;
 
133
      if ((dict = value as PdfDictionary) != null)
 
134
        EncryptDictionary(dict);
 
135
      else if ((array = value as PdfArray) != null)
 
136
        EncryptArray(array);
 
137
      else if ((str = value as PdfStringObject) != null)
 
138
      {
 
139
        if (str.Length != 0)
 
140
        {
 
141
          byte[] bytes = str.EncryptionValue;
 
142
          PrepareKey();
 
143
          EncryptRC4(bytes);
 
144
          str.EncryptionValue = bytes;
 
145
        }
 
146
      }
 
147
    }
 
148
 
 
149
    /// <summary>
 
150
    /// Encrypts a dictionary.
 
151
    /// </summary>
 
152
    void EncryptDictionary(PdfDictionary dict)
 
153
    {
 
154
      PdfName[] names = dict.Elements.KeyNames;
 
155
      foreach (DictionaryEntry item in dict.Elements)
 
156
      {
 
157
        PdfString value1;
 
158
        PdfDictionary value2;
 
159
        PdfArray value3;
 
160
        if ((value1 = item.Value as PdfString) != null)
 
161
          EncryptString(value1);
 
162
        else if ((value2 = item.Value as PdfDictionary) != null)
 
163
          EncryptDictionary(value2);
 
164
        else if ((value3 = item.Value as PdfArray) != null)
 
165
          EncryptArray(value3);
 
166
      }
 
167
      if (dict.Stream != null)
 
168
      {
 
169
        byte[] bytes = dict.Stream.Value;
 
170
        if (bytes.Length != 0)
 
171
        {
 
172
          PrepareKey();
 
173
          EncryptRC4(bytes);
 
174
          dict.Stream.Value = bytes;
 
175
        }
 
176
      }
 
177
    }
 
178
 
 
179
    /// <summary>
 
180
    /// Encrypts an array.
 
181
    /// </summary>
 
182
    void EncryptArray(PdfArray array)
 
183
    {
 
184
      int count = array.Elements.Count;
 
185
      for (int idx = 0; idx < count; idx++)
 
186
      {
 
187
        PdfItem item = array.Elements[idx];
 
188
        PdfString value1;
 
189
        PdfDictionary value2;
 
190
        PdfArray value3;
 
191
        if ((value1 = item as PdfString) != null)
 
192
          EncryptString(value1);
 
193
        else if ((value2 = item as PdfDictionary) != null)
 
194
          EncryptDictionary(value2);
 
195
        else if ((value3 = item as PdfArray) != null)
 
196
          EncryptArray(value3);
 
197
      }
 
198
    }
 
199
 
 
200
    /// <summary>
 
201
    /// Encrypts a string.
 
202
    /// </summary>
 
203
    void EncryptString(PdfString value)
 
204
    {
 
205
      if (value.Length != 0)
 
206
      {
 
207
        byte[] bytes = value.EncryptionValue;
 
208
        PrepareKey();
 
209
        EncryptRC4(bytes);
 
210
        value.EncryptionValue = bytes;
 
211
      }
 
212
    }
 
213
 
 
214
    /// <summary>
 
215
    /// Encrypts an array.
 
216
    /// </summary>
 
217
    internal byte[] EncryptBytes(byte[] bytes)
 
218
    {
 
219
      if (bytes != null && bytes.Length != 0)
 
220
      {
 
221
        PrepareKey();
 
222
        EncryptRC4(bytes);
 
223
      }
 
224
      return bytes;
 
225
    }
 
226
 
 
227
    #region Encryption Algorithms
 
228
 
 
229
    /// <summary>
 
230
    /// Checks the password.
 
231
    /// </summary>
 
232
    /// <param name="inputPassword">Password or null if no password is provided.</param>
 
233
    /// <returns>
 
234
    /// 0: inputPassword is neither user nor owner password.
 
235
    /// 1: inputPassword is user password.
 
236
    /// 2: inputPassword is owner password.
 
237
    /// </returns>
 
238
    public int ValidatePassword(string inputPassword)
 
239
    {
 
240
      // We can handle 40 and 128 bit standard encryption
 
241
      string filter = Elements.GetName(PdfSecurityHandler.Keys.Filter);
 
242
      int v = Elements.GetInteger(Keys.V);
 
243
      if (filter != "/Standard" || !(v >= 1 && v <= 3))
 
244
        throw new PdfReaderException(PSSR.UnknownEncryption);
 
245
 
 
246
      byte[] documentID = PdfEncoders.RawEncoding.GetBytes(Owner.Internals.FirstDocumentID);
 
247
      byte[] oValue = PdfEncoders.RawEncoding.GetBytes(Elements.GetString(Keys.O));
 
248
      byte[] uValue = PdfEncoders.RawEncoding.GetBytes(Elements.GetString(Keys.U));
 
249
      int pValue = Elements.GetInteger(Keys.P);
 
250
      int rValue = Elements.GetInteger(Keys.R);
 
251
 
 
252
      byte[] password;
 
253
      if (inputPassword == null)
 
254
        inputPassword = "";
 
255
 
 
256
      bool strongEncryption = rValue == 3;
 
257
      int keyLength = strongEncryption ? 16 : 32;
 
258
 
 
259
      password = PdfEncoders.RawEncoding.GetBytes(inputPassword);
 
260
      InitWidhUserPassword(documentID, inputPassword, oValue, pValue, strongEncryption);
 
261
 
 
262
      this.document.SecuritySettings.hasOwnerPermissions = false;
 
263
 
 
264
      if (!EqualsKey(uValue, keyLength))
 
265
      {
 
266
        password = PdfEncoders.RawEncoding.GetBytes(inputPassword);
 
267
 
 
268
        //Compare owner password
 
269
        InitWidhOwnerPassword(documentID, inputPassword, oValue, pValue, strongEncryption);
 
270
 
 
271
        if (!EqualsKey(uValue, keyLength))
 
272
        {
 
273
          //Compare user password
 
274
          InitWidhUserPassword(documentID, inputPassword, oValue, pValue, strongEncryption);
 
275
          if (!EqualsKey(uValue, keyLength))
 
276
            return 0;
 
277
          return 1;
 
278
        }
 
279
        this.document.SecuritySettings.hasOwnerPermissions = true;
 
280
        return 2;
 
281
      }
 
282
      return 1;
 
283
    }
 
284
 
 
285
    [Conditional("DEBUG")]
 
286
    void DumpBytes(string tag, byte[] bytes)
 
287
    {
 
288
      string dump = tag + ": ";
 
289
      for (int idx = 0; idx < bytes.Length; idx++)
 
290
        dump += String.Format("{0:X2}", bytes[idx]);
 
291
      Debug.WriteLine(dump);
 
292
    }
 
293
 
 
294
    /// <summary>
 
295
    /// Pads a password to a 32 byte array.
 
296
    /// </summary>
 
297
    byte[] PadPassword(string password)
 
298
    {
 
299
      byte[] padded = new byte[32];
 
300
      if (password == null)
 
301
        Array.Copy(passwordPadding, 0, padded, 0, 32);
 
302
      else
 
303
      {
 
304
        int length = password.Length;
 
305
        Array.Copy(PdfEncoders.RawEncoding.GetBytes(password), 0, padded, 0, Math.Min(length, 32));
 
306
        if (length < 32)
 
307
          Array.Copy(passwordPadding, 0, padded, length, 32 - length);
 
308
      }
 
309
      return padded;
 
310
    }
 
311
    static byte[] passwordPadding = // 32 bytes password padding defined by Adobe
 
312
    {
 
313
      0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
 
314
      0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
 
315
    };
 
316
 
 
317
    /// <summary>
 
318
    /// Generates the user key based on the padded user password.
 
319
    /// </summary>
 
320
    void InitWidhUserPassword(byte[] documentID, string userPassword, byte[] ownerKey, int permissions, bool strongEncryption)
 
321
    {
 
322
      InitEncryptionKey(documentID, PadPassword(userPassword), ownerKey, permissions, strongEncryption);
 
323
      SetupUserKey(documentID);
 
324
    }
 
325
 
 
326
    /// <summary>
 
327
    /// Generates the user key based on the padded owner password.
 
328
    /// </summary>
 
329
    void InitWidhOwnerPassword(byte[] documentID, string ownerPassword, byte[] ownerKey, int permissions, bool strongEncryption)
 
330
    {
 
331
      byte[] userPad = ComputeOwnerKey(ownerKey, PadPassword(ownerPassword), strongEncryption);
 
332
      InitEncryptionKey(documentID, userPad, ownerKey, permissions, strongEncryption);
 
333
      SetupUserKey(documentID);
 
334
    }
 
335
 
 
336
    /// <summary>
 
337
    /// Computes the padded user password from the padded owner password.
 
338
    /// </summary>
 
339
    byte[] ComputeOwnerKey(byte[] userPad, byte[] ownerPad, bool strongEncryption)
 
340
    {
 
341
      byte[] ownerKey = new byte[32];
 
342
 
 
343
      byte[] digest = this.md5.ComputeHash(ownerPad);
 
344
      if (strongEncryption)
 
345
      {
 
346
        byte[] mkey = new byte[16];
 
347
        // Hash the pad 50 times
 
348
        for (int idx = 0; idx < 50; idx++)
 
349
          digest = this.md5.ComputeHash(digest);
 
350
        Array.Copy(userPad, 0, ownerKey, 0, 32);
 
351
        // Encrypt the key
 
352
        for (int i = 0; i < 20; i++)
 
353
        {
 
354
          for (int j = 0; j < mkey.Length; ++j)
 
355
            mkey[j] = (byte)(digest[j] ^ i);
 
356
          PrepareRC4Key(mkey);
 
357
          EncryptRC4(ownerKey);
 
358
        }
 
359
      }
 
360
      else
 
361
      {
 
362
        PrepareRC4Key(digest, 0, 5);
 
363
        EncryptRC4(userPad, ownerKey);
 
364
      }
 
365
      return ownerKey;
 
366
    }
 
367
 
 
368
    /// <summary>
 
369
    /// Computes the encryption key.
 
370
    /// </summary>
 
371
    void InitEncryptionKey(byte[] documentID, byte[] userPad, byte[] ownerKey, int permissions, bool strongEncryption)
 
372
    {
 
373
      this.ownerKey = ownerKey;
 
374
      this.encryptionKey = new byte[strongEncryption ? 16 : 5];
 
375
 
 
376
      this.md5.Initialize();
 
377
      this.md5.TransformBlock(userPad, 0, userPad.Length, userPad, 0);
 
378
      this.md5.TransformBlock(ownerKey, 0, ownerKey.Length, ownerKey, 0);
 
379
 
 
380
      // Split permission into 4 bytes
 
381
      byte[] permission = new byte[4];
 
382
      permission[0] = (byte)permissions;
 
383
      permission[1] = (byte)(permissions >> 8);
 
384
      permission[2] = (byte)(permissions >> 16);
 
385
      permission[3] = (byte)(permissions >> 24);
 
386
      this.md5.TransformBlock(permission, 0, 4, permission, 0);
 
387
      this.md5.TransformBlock(documentID, 0, documentID.Length, documentID, 0);
 
388
      this.md5.TransformFinalBlock(permission, 0, 0);
 
389
      byte[] digest = this.md5.Hash;
 
390
      this.md5.Initialize();
 
391
      // Create the hash 50 times (only for 128 bit)
 
392
      if (this.encryptionKey.Length == 16)
 
393
      {
 
394
        for (int idx = 0; idx < 50; idx++)
 
395
        {
 
396
          digest = this.md5.ComputeHash(digest);
 
397
          this.md5.Initialize();
 
398
        }
 
399
      }
 
400
      Array.Copy(digest, 0, this.encryptionKey, 0, this.encryptionKey.Length);
 
401
    }
 
402
 
 
403
    /// <summary>
 
404
    /// Computes the user key.
 
405
    /// </summary>
 
406
    void SetupUserKey(byte[] documentID)
 
407
    {
 
408
      if (this.encryptionKey.Length == 16)
 
409
      {
 
410
        this.md5.TransformBlock(passwordPadding, 0, passwordPadding.Length, passwordPadding, 0);
 
411
        this.md5.TransformFinalBlock(documentID, 0, documentID.Length);
 
412
        byte[] digest = this.md5.Hash;
 
413
        this.md5.Initialize();
 
414
        Array.Copy(digest, 0, this.userKey, 0, 16);
 
415
        for (int idx = 16; idx < 32; idx++)
 
416
          this.userKey[idx] = 0;
 
417
        //Encrypt the key
 
418
        for (int i = 0; i < 20; i++)
 
419
        {
 
420
          for (int j = 0; j < this.encryptionKey.Length; j++)
 
421
            digest[j] = (byte)(this.encryptionKey[j] ^ i);
 
422
          PrepareRC4Key(digest, 0, this.encryptionKey.Length);
 
423
          EncryptRC4(this.userKey, 0, 16);
 
424
        }
 
425
      }
 
426
      else
 
427
      {
 
428
        PrepareRC4Key(this.encryptionKey);
 
429
        EncryptRC4(passwordPadding, this.userKey);
 
430
      }
 
431
    }
 
432
 
 
433
    /// <summary>
 
434
    /// Prepare the encryption key.
 
435
    /// </summary>
 
436
    void PrepareKey()
 
437
    {
 
438
      PrepareRC4Key(this.key, 0, this.keySize);
 
439
    }
 
440
 
 
441
    /// <summary>
 
442
    /// Prepare the encryption key.
 
443
    /// </summary>
 
444
    void PrepareRC4Key(byte[] key)
 
445
    {
 
446
      PrepareRC4Key(key, 0, key.Length);
 
447
    }
 
448
 
 
449
    /// <summary>
 
450
    /// Prepare the encryption key.
 
451
    /// </summary>
 
452
    void PrepareRC4Key(byte[] key, int offset, int length)
 
453
    {
 
454
      int idx1 = 0;
 
455
      int idx2 = 0;
 
456
      for (int idx = 0; idx < 256; idx++)
 
457
        this.state[idx] = (byte)idx;
 
458
      byte tmp;
 
459
      for (int idx = 0; idx < 256; idx++)
 
460
      {
 
461
        idx2 = (key[idx1 + offset] + this.state[idx] + idx2) & 255;
 
462
        tmp = this.state[idx];
 
463
        this.state[idx] = this.state[idx2];
 
464
        this.state[idx2] = tmp;
 
465
        idx1 = (idx1 + 1) % length;
 
466
      }
 
467
    }
 
468
 
 
469
    /// <summary>
 
470
    /// Encrypts the data.
 
471
    /// </summary>
 
472
    void EncryptRC4(byte[] data)
 
473
    {
 
474
      EncryptRC4(data, 0, data.Length, data);
 
475
    }
 
476
 
 
477
    /// <summary>
 
478
    /// Encrypts the data.
 
479
    /// </summary>
 
480
    void EncryptRC4(byte[] data, int offset, int length)
 
481
    {
 
482
      EncryptRC4(data, offset, length, data);
 
483
    }
 
484
 
 
485
    /// <summary>
 
486
    /// Encrypts the data.
 
487
    /// </summary>
 
488
    void EncryptRC4(byte[] inputData, byte[] outputData)
 
489
    {
 
490
      EncryptRC4(inputData, 0, inputData.Length, outputData);
 
491
    }
 
492
 
 
493
    /// <summary>
 
494
    /// Encrypts the data.
 
495
    /// </summary>
 
496
    void EncryptRC4(byte[] inputData, int offset, int length, byte[] outputData)
 
497
    {
 
498
      length += offset;
 
499
      int x = 0, y = 0;
 
500
      byte b;
 
501
      for (int idx = offset; idx < length; idx++)
 
502
      {
 
503
        x = (x + 1) & 255;
 
504
        y = (this.state[x] + y) & 255;
 
505
        b = this.state[x];
 
506
        this.state[x] = this.state[y];
 
507
        this.state[y] = b;
 
508
        outputData[idx] = (byte)(inputData[idx] ^ state[(this.state[x] + this.state[y]) & 255]);
 
509
      }
 
510
    }
 
511
 
 
512
    /// <summary>
 
513
    /// Checks whether the calculated key correct.
 
514
    /// </summary>
 
515
    bool EqualsKey(byte[] value, int length)
 
516
    {
 
517
      for (int idx = 0; idx < length; idx++)
 
518
      {
 
519
        if (this.userKey[idx] != value[idx])
 
520
          return false;
 
521
      }
 
522
      return true;
 
523
    }
 
524
 
 
525
    /// <summary>
 
526
    /// Set the hash key for the specified object.
 
527
    /// </summary>
 
528
    internal void SetHashKey(PdfObjectID id)
 
529
    {
 
530
      byte[] objectId = new byte[5];
 
531
      this.md5.Initialize();
 
532
      // Split the object number and generation
 
533
      objectId[0] = (byte)id.ObjectNumber;
 
534
      objectId[1] = (byte)(id.ObjectNumber >> 8);
 
535
      objectId[2] = (byte)(id.ObjectNumber >> 16);
 
536
      objectId[3] = (byte)id.GenerationNumber;
 
537
      objectId[4] = (byte)(id.GenerationNumber >> 8);
 
538
      this.md5.TransformBlock(this.encryptionKey, 0, this.encryptionKey.Length, this.encryptionKey, 0);
 
539
      this.md5.TransformFinalBlock(objectId, 0, objectId.Length);
 
540
      this.key = this.md5.Hash;
 
541
      this.md5.Initialize();
 
542
      this.keySize = this.encryptionKey.Length + 5;
 
543
      if (this.keySize > 16)
 
544
        this.keySize = 16;
 
545
    }
 
546
 
 
547
    /// <summary>
 
548
    /// Prepares the security handler for encrypting the document.
 
549
    /// </summary>
 
550
    public void PrepareEncryption()
 
551
    {
 
552
      Debug.Assert(this.document.securitySettings.DocumentSecurityLevel != PdfDocumentSecurityLevel.None);
 
553
      int permissions = (int)this.Permission;
 
554
      bool strongEncryption = this.document.securitySettings.DocumentSecurityLevel == PdfDocumentSecurityLevel.Encrypted128Bit;
 
555
 
 
556
      PdfInteger vValue;
 
557
      PdfInteger length;
 
558
      PdfInteger rValue;
 
559
 
 
560
      if (strongEncryption)
 
561
      {
 
562
        vValue = new PdfInteger(2);
 
563
        length = new PdfInteger(128);
 
564
        rValue = new PdfInteger(3);
 
565
      }
 
566
      else
 
567
      {
 
568
        vValue = new PdfInteger(1);
 
569
        length = new PdfInteger(40);
 
570
        rValue = new PdfInteger(2);
 
571
      }
 
572
 
 
573
      if (this.userPassword == null || this.userPassword.Length == 0)
 
574
        this.userPassword = "";
 
575
      // Use user password twice if no owner password provided.
 
576
      if (this.ownerPassword == null || this.ownerPassword.Length == 0)
 
577
        this.ownerPassword = this.userPassword;
 
578
 
 
579
      // Correct permission bits
 
580
      permissions |= (int)(strongEncryption ? (uint)0xfffff0c0 : (uint)0xffffffc0);
 
581
      permissions &= unchecked((int)0xfffffffc);
 
582
 
 
583
      PdfInteger pValue = new PdfInteger(permissions);
 
584
 
 
585
      Debug.Assert(this.ownerPassword.Length > 0, "Empty owner password.");
 
586
      byte[] userPad = PadPassword(this.userPassword);
 
587
      byte[] ownerPad = PadPassword(this.ownerPassword);
 
588
 
 
589
      this.md5.Initialize();
 
590
      this.ownerKey = ComputeOwnerKey(userPad, ownerPad, strongEncryption);
 
591
      byte[] documentID = PdfEncoders.RawEncoding.GetBytes(this.document.Internals.FirstDocumentID);
 
592
      InitWidhUserPassword(documentID, this.userPassword, this.ownerKey, permissions, strongEncryption);
 
593
 
 
594
      PdfString oValue = new PdfString(PdfEncoders.RawEncoding.GetString(this.ownerKey));
 
595
      PdfString uValue = new PdfString(PdfEncoders.RawEncoding.GetString(this.userKey));
 
596
 
 
597
      Elements[Keys.Filter] = new PdfName("/Standard");
 
598
      Elements[Keys.V] = vValue;
 
599
      Elements[Keys.Length] = length;
 
600
      Elements[Keys.R] = rValue;
 
601
      Elements[Keys.O] = oValue;
 
602
      Elements[Keys.U] = uValue;
 
603
      Elements[Keys.P] = pValue;
 
604
    }
 
605
 
 
606
    /// <summary>
 
607
    /// The global encryption key.
 
608
    /// </summary>
 
609
    byte[] encryptionKey;
 
610
 
 
611
    /// <summary>
 
612
    /// The message digest algorithm MD5.
 
613
    /// </summary>
 
614
    MD5 md5 = new MD5CryptoServiceProvider();
 
615
 
 
616
    /// <summary>
 
617
    /// Bytes used for RC4 encryption.
 
618
    /// </summary>
 
619
    byte[] state = new byte[256];
 
620
 
 
621
    /// <summary>
 
622
    /// The encryption key for the owner.
 
623
    /// </summary>
 
624
    byte[] ownerKey = new byte[32];
 
625
 
 
626
    /// <summary>
 
627
    /// The encryption key for the user.
 
628
    /// </summary>
 
629
    byte[] userKey = new byte[32];
 
630
 
 
631
    /// <summary>
 
632
    /// The encryption key for a particular object/generation.
 
633
    /// </summary>
 
634
    byte[] key;
 
635
 
 
636
    /// <summary>
 
637
    /// The encryption key length for a particular object/generation.
 
638
    /// </summary>
 
639
    int keySize;
 
640
 
 
641
    #endregion
 
642
 
 
643
    internal override void WriteObject(PdfWriter writer)
 
644
    {
 
645
      // Don't encypt myself
 
646
      PdfStandardSecurityHandler securityHandler = writer.SecurityHandler;
 
647
      writer.SecurityHandler = null;
 
648
      base.WriteObject(writer);
 
649
      writer.SecurityHandler = securityHandler;
 
650
    }
 
651
 
 
652
    #region Keys
 
653
    /// <summary>
 
654
    /// Predefined keys of this dictionary.
 
655
    /// </summary>
 
656
    internal sealed new class Keys : PdfSecurityHandler.Keys
 
657
    {
 
658
      /// <summary>
 
659
      /// (Required) A number specifying which revision of the standard security handler
 
660
      /// should be used to interpret this dictionary:
 
661
      /// � 2 if the document is encrypted with a V value less than 2 and does not have any of
 
662
      ///   the access permissions set (by means of the P entry, below) that are designated 
 
663
      ///   "Revision 3 or greater".
 
664
      /// � 3 if the document is encrypted with a V value of 2 or 3, or has any "Revision 3 or 
 
665
      ///   greater" access permissions set.
 
666
      /// � 4 if the document is encrypted with a V value of 4
 
667
      /// </summary>
 
668
      [KeyInfo(KeyType.Integer | KeyType.Required)]
 
669
      public const string R = "/R";
 
670
 
 
671
      /// <summary>
 
672
      /// (Required) A 32-byte string, based on both the owner and user passwords, that is
 
673
      /// used in computing the encryption key and in determining whether a valid owner
 
674
      /// password was entered.
 
675
      /// </summary>
 
676
      [KeyInfo(KeyType.String | KeyType.Required)]
 
677
      public const string O = "/O";
 
678
 
 
679
      /// <summary>
 
680
      /// (Required) A 32-byte string, based on the user password, that is used in determining
 
681
      /// whether to prompt the user for a password and, if so, whether a valid user or owner 
 
682
      /// password was entered.
 
683
      /// </summary>
 
684
      [KeyInfo(KeyType.String | KeyType.Required)]
 
685
      public const string U = "/U";
 
686
 
 
687
      /// <summary>
 
688
      /// (Required) A set of flags specifying which operations are permitted when the document
 
689
      /// is opened with user access.
 
690
      /// </summary>
 
691
      [KeyInfo(KeyType.Integer | KeyType.Required)]
 
692
      public const string P = "/P";
 
693
 
 
694
      /// <summary>
 
695
      /// (Optional; meaningful only when the value of V is 4; PDF 1.5) Indicates whether
 
696
      /// the document-level metadata stream is to be encrypted. Applications should respect this value.
 
697
      /// Default value: true.
 
698
      /// </summary>
 
699
      [KeyInfo(KeyType.Boolean | KeyType.Optional)]
 
700
      public const string EncryptMetadata = "/EncryptMetadata";
 
701
 
 
702
      /// <summary>
 
703
      /// Gets the KeysMeta for these keys.
 
704
      /// </summary>
 
705
      public static DictionaryMeta Meta
 
706
      {
 
707
        get
 
708
        {
 
709
          if (Keys.meta == null)
 
710
            Keys.meta = CreateMeta(typeof(Keys));
 
711
          return Keys.meta;
 
712
        }
 
713
      }
 
714
      static DictionaryMeta meta;
 
715
    }
 
716
 
 
717
    /// <summary>
 
718
    /// Gets the KeysMeta of this dictionary type.
 
719
    /// </summary>
 
720
    internal override DictionaryMeta Meta
 
721
    {
 
722
      get { return Keys.Meta; }
 
723
    }
 
724
    #endregion
 
725
  }
 
726
}