First commit

Send all results
This commit is contained in:
2020-09-04 12:49:15 +05:00
commit 330a2ccfda
2819 changed files with 226201 additions and 0 deletions

View File

@@ -0,0 +1,426 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
// Based on code from here:
// http://archive.msdn.microsoft.com/SilverlightMD5/Release/ProjectReleases.aspx?ReleaseId=2206
//
// **************************************************************
// * Raw implementation of the MD5 hash algorithm
// * from RFC 1321.
// *
// * Written By: Reid Borsuk and Jenny Zheng
// * Copyright (c) Microsoft Corporation. All rights reserved.
// **************************************************************
using System;
using System.Diagnostics;
#if !NETFX_CORE && !UWP
using System.Security.Cryptography;
#endif
// ReSharper disable InconsistentNaming
#if SILVERLIGHT || WINDOWS_PHONE || UWP || (GDI && DEBUG)
namespace PdfSharp.Pdf.Security
{
#if UWP
class HashAlgorithm
{
public int HashSizeValue { get; set; }
public virtual void Initialize()
{ }
protected virtual void HashCore(byte[] array, int ibStart, int cbSize)
{ }
protected virtual byte[] HashFinal()
{
return null;
}
public byte[] HashValue { get; set; }
public void TransformBlock(byte[] a, int b, int c, byte[] d, int e)
{ }
public void TransformFinalBlock(byte[] a, int b, int c)
{ }
public byte[] ComputeHash(byte[] a)
{
return null;
}
public byte[] Hash
{
get { return null; }
}
}
#endif
/// <summary>
/// A managed implementation of the MD5 algorithm.
/// Necessary because MD5 is not part of the framework in Silverlight and WP.
/// </summary>
class MD5Managed
//#if !UWP
: HashAlgorithm // TODO: WinRT has not even a HashAlgorithm base class.
//#endif
{
// Intitial values as defined in RFC 1321.
const uint A = 0x67452301;
const uint B = 0xefcdab89;
const uint C = 0x98badcfe;
const uint D = 0x10325476;
public MD5Managed()
{
HashSizeValue = 128;
Initialize();
}
public sealed override void Initialize()
{
_data = new byte[64];
_dataSize = 0;
_totalLength = 0;
_abcd = new MD5Core.ABCDStruct();
// Intitial values as defined in RFC 1321.
_abcd.A = A;
_abcd.B = B;
_abcd.C = C;
_abcd.D = D;
}
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
int startIndex = ibStart;
int totalArrayLength = _dataSize + cbSize;
if (totalArrayLength >= 64)
{
Array.Copy(array, startIndex, _data, _dataSize, 64 - _dataSize);
// Process message of 64 bytes (512 bits)
MD5Core.GetHashBlock(_data, ref _abcd, 0);
startIndex += 64 - _dataSize;
totalArrayLength -= 64;
while (totalArrayLength >= 64)
{
Array.Copy(array, startIndex, _data, 0, 64);
MD5Core.GetHashBlock(array, ref _abcd, startIndex);
totalArrayLength -= 64;
startIndex += 64;
}
_dataSize = totalArrayLength;
Array.Copy(array, startIndex, _data, 0, totalArrayLength);
}
else
{
Array.Copy(array, startIndex, _data, _dataSize, cbSize);
_dataSize = totalArrayLength;
}
_totalLength += cbSize;
}
protected override byte[] HashFinal()
{
HashValue = MD5Core.GetHashFinalBlock(_data, 0, _dataSize, _abcd, _totalLength * 8);
return HashValue;
}
byte[] _data;
MD5Core.ABCDStruct _abcd;
Int64 _totalLength;
int _dataSize;
static class MD5Core
{
#if true
public static byte[] GetHash(byte[] input)
{
if (null == input)
throw new ArgumentNullException("input");
// Intitial values defined in RFC 1321.
ABCDStruct abcd = new ABCDStruct();
abcd.A = A;
abcd.B = B;
abcd.C = C;
abcd.D = D;
// We pass in the input array by block, the final block of data must be handled specially for padding & length embeding.
int startIndex = 0;
while (startIndex <= input.Length - 64)
{
GetHashBlock(input, ref abcd, startIndex);
startIndex += 64;
}
// The final data block.
return GetHashFinalBlock(input, startIndex, input.Length - startIndex, abcd, (Int64)input.Length * 8);
}
#endif
internal static byte[] GetHashFinalBlock(byte[] input, int ibStart, int cbSize, ABCDStruct abcd, Int64 len)
{
byte[] working = new byte[64];
byte[] length = BitConverter.GetBytes(len);
// Padding is a single bit 1, followed by the number of 0s required to make size congruent to 448 modulo 512. Step 1 of RFC 1321
// The CLR ensures that our buffer is 0-assigned, we don't need to explicitly set it. This is why it ends up being quicker to just
// use a temporary array rather then doing in-place assignment (5% for small inputs)
Array.Copy(input, ibStart, working, 0, cbSize);
working[cbSize] = 0x80;
// We have enough room to store the length in this chunk.
if (cbSize <= 56)
{
Array.Copy(length, 0, working, 56, 8);
GetHashBlock(working, ref abcd, 0);
}
else // We need an aditional chunk to store the length.
{
GetHashBlock(working, ref abcd, 0);
// Create an entirely new chunk due to the 0-assigned trick mentioned above, to avoid an extra function call clearing the array.
working = new byte[64];
Array.Copy(length, 0, working, 56, 8);
GetHashBlock(working, ref abcd, 0);
}
byte[] output = new byte[16];
Array.Copy(BitConverter.GetBytes(abcd.A), 0, output, 0, 4);
Array.Copy(BitConverter.GetBytes(abcd.B), 0, output, 4, 4);
Array.Copy(BitConverter.GetBytes(abcd.C), 0, output, 8, 4);
Array.Copy(BitConverter.GetBytes(abcd.D), 0, output, 12, 4);
return output;
}
internal static void GetHashBlock(byte[] input, ref ABCDStruct ABCDValue, int ibStart)
{
uint[] temp = Converter(input, ibStart);
uint a = ABCDValue.A;
uint b = ABCDValue.B;
uint c = ABCDValue.C;
uint d = ABCDValue.D;
a = r1(a, b, c, d, temp[0], 7, 0xd76aa478);
d = r1(d, a, b, c, temp[1], 12, 0xe8c7b756);
c = r1(c, d, a, b, temp[2], 17, 0x242070db);
b = r1(b, c, d, a, temp[3], 22, 0xc1bdceee);
a = r1(a, b, c, d, temp[4], 7, 0xf57c0faf);
d = r1(d, a, b, c, temp[5], 12, 0x4787c62a);
c = r1(c, d, a, b, temp[6], 17, 0xa8304613);
b = r1(b, c, d, a, temp[7], 22, 0xfd469501);
a = r1(a, b, c, d, temp[8], 7, 0x698098d8);
d = r1(d, a, b, c, temp[9], 12, 0x8b44f7af);
c = r1(c, d, a, b, temp[10], 17, 0xffff5bb1);
b = r1(b, c, d, a, temp[11], 22, 0x895cd7be);
a = r1(a, b, c, d, temp[12], 7, 0x6b901122);
d = r1(d, a, b, c, temp[13], 12, 0xfd987193);
c = r1(c, d, a, b, temp[14], 17, 0xa679438e);
b = r1(b, c, d, a, temp[15], 22, 0x49b40821);
a = r2(a, b, c, d, temp[1], 5, 0xf61e2562);
d = r2(d, a, b, c, temp[6], 9, 0xc040b340);
c = r2(c, d, a, b, temp[11], 14, 0x265e5a51);
b = r2(b, c, d, a, temp[0], 20, 0xe9b6c7aa);
a = r2(a, b, c, d, temp[5], 5, 0xd62f105d);
d = r2(d, a, b, c, temp[10], 9, 0x02441453);
c = r2(c, d, a, b, temp[15], 14, 0xd8a1e681);
b = r2(b, c, d, a, temp[4], 20, 0xe7d3fbc8);
a = r2(a, b, c, d, temp[9], 5, 0x21e1cde6);
d = r2(d, a, b, c, temp[14], 9, 0xc33707d6);
c = r2(c, d, a, b, temp[3], 14, 0xf4d50d87);
b = r2(b, c, d, a, temp[8], 20, 0x455a14ed);
a = r2(a, b, c, d, temp[13], 5, 0xa9e3e905);
d = r2(d, a, b, c, temp[2], 9, 0xfcefa3f8);
c = r2(c, d, a, b, temp[7], 14, 0x676f02d9);
b = r2(b, c, d, a, temp[12], 20, 0x8d2a4c8a);
a = r3(a, b, c, d, temp[5], 4, 0xfffa3942);
d = r3(d, a, b, c, temp[8], 11, 0x8771f681);
c = r3(c, d, a, b, temp[11], 16, 0x6d9d6122);
b = r3(b, c, d, a, temp[14], 23, 0xfde5380c);
a = r3(a, b, c, d, temp[1], 4, 0xa4beea44);
d = r3(d, a, b, c, temp[4], 11, 0x4bdecfa9);
c = r3(c, d, a, b, temp[7], 16, 0xf6bb4b60);
b = r3(b, c, d, a, temp[10], 23, 0xbebfbc70);
a = r3(a, b, c, d, temp[13], 4, 0x289b7ec6);
d = r3(d, a, b, c, temp[0], 11, 0xeaa127fa);
c = r3(c, d, a, b, temp[3], 16, 0xd4ef3085);
b = r3(b, c, d, a, temp[6], 23, 0x04881d05);
a = r3(a, b, c, d, temp[9], 4, 0xd9d4d039);
d = r3(d, a, b, c, temp[12], 11, 0xe6db99e5);
c = r3(c, d, a, b, temp[15], 16, 0x1fa27cf8);
b = r3(b, c, d, a, temp[2], 23, 0xc4ac5665);
a = r4(a, b, c, d, temp[0], 6, 0xf4292244);
d = r4(d, a, b, c, temp[7], 10, 0x432aff97);
c = r4(c, d, a, b, temp[14], 15, 0xab9423a7);
b = r4(b, c, d, a, temp[5], 21, 0xfc93a039);
a = r4(a, b, c, d, temp[12], 6, 0x655b59c3);
d = r4(d, a, b, c, temp[3], 10, 0x8f0ccc92);
c = r4(c, d, a, b, temp[10], 15, 0xffeff47d);
b = r4(b, c, d, a, temp[1], 21, 0x85845dd1);
a = r4(a, b, c, d, temp[8], 6, 0x6fa87e4f);
d = r4(d, a, b, c, temp[15], 10, 0xfe2ce6e0);
c = r4(c, d, a, b, temp[6], 15, 0xa3014314);
b = r4(b, c, d, a, temp[13], 21, 0x4e0811a1);
a = r4(a, b, c, d, temp[4], 6, 0xf7537e82);
d = r4(d, a, b, c, temp[11], 10, 0xbd3af235);
c = r4(c, d, a, b, temp[2], 15, 0x2ad7d2bb);
b = r4(b, c, d, a, temp[9], 21, 0xeb86d391);
ABCDValue.A = unchecked(a + ABCDValue.A);
ABCDValue.B = unchecked(b + ABCDValue.B);
ABCDValue.C = unchecked(c + ABCDValue.C);
ABCDValue.D = unchecked(d + ABCDValue.D);
}
// Manually unrolling these equations nets us a 20% performance improvement
private static uint r1(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + F(b, c, d) + x + t), s))
// F(x, y, z) ((x & y) | ((x ^ 0xFFFFFFFF) & z))
return unchecked(b + LSR((a + ((b & c) | ((b ^ 0xFFFFFFFF) & d)) + x + t), s));
}
private static uint r2(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + G(b, c, d) + x + t), s))
// G(x, y, z) ((x & z) | (y & (z ^ 0xFFFFFFFF)))
return unchecked(b + LSR((a + ((b & d) | (c & (d ^ 0xFFFFFFFF))) + x + t), s));
}
private static uint r3(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + H(b, c, d) + k + i), s))
// H(x, y, z) (x ^ y ^ z)
return unchecked(b + LSR((a + (b ^ c ^ d) + x + t), s));
}
private static uint r4(uint a, uint b, uint c, uint d, uint x, int s, uint t)
{
// (b + LSR((a + I(b, c, d) + k + i), s))
// I(x, y, z) (y ^ (x | (z ^ 0xFFFFFFFF)))
return unchecked(b + LSR((a + (c ^ (b | (d ^ 0xFFFFFFFF))) + x + t), s));
}
// Implementation of left rotate
// s is an int instead of a uint becuase the CLR requires the argument passed to >>/<< is of
// type int. Doing the demoting inside this function would add overhead.
private static uint LSR(uint i, int s)
{
return (i << s) | (i >> (32 - s));
}
// Convert input array into array of UInts.
static uint[] Converter(byte[] input, int ibStart)
{
if (null == input)
throw new ArgumentNullException("input");
uint[] result = new uint[16];
for (int idx = 0; idx < 16; idx++)
{
result[idx] = (uint)input[ibStart + idx * 4];
result[idx] += (uint)input[ibStart + idx * 4 + 1] << 8;
result[idx] += (uint)input[ibStart + idx * 4 + 2] << 16;
result[idx] += (uint)input[ibStart + idx * 4 + 3] << 24;
Debug.Assert(result[idx] ==
(input[ibStart + idx * 4]) +
((uint)input[ibStart + idx * 4 + 1] << 8) +
((uint)input[ibStart + idx * 4 + 2] << 16) +
((uint)input[ibStart + idx * 4 + 3] << 24));
}
return result;
}
// Simple struct for the (a,b,c,d) which is used to compute the mesage digest.
public struct ABCDStruct
{
public uint A;
public uint B;
public uint C;
public uint D;
}
}
}
#if GDI && DEBUG && true_
// See here for details: http://archive.msdn.microsoft.com/SilverlightMD5/WorkItem/View.aspx?WorkItemId=3
public static class TestMD5
{
public static void Test()
{
Random rnd = new Random();
for (int i = 0; i < 10000; i++)
{
int count = rnd.Next(1000) + 1;
Console.WriteLine(String.Format("{0}: {1}", i, count));
Test2(count);
}
}
static void Test2(int count)
{
byte[] bytes = new byte[count];
for (int idx = 0; idx < count; idx += 16)
Array.Copy(Guid.NewGuid().ToByteArray(), 0, bytes, idx, Math.Min(16, count - idx));
MD5 md5dotNet = new MD5CryptoServiceProvider();
md5dotNet.Initialize();
MD5Managed md5m = new MD5Managed();
md5m.Initialize();
byte[] result1 = md5dotNet.ComputeHash(bytes);
byte[] result2 = md5m.ComputeHash(bytes);
if (!CompareBytes(result1, result2))
{
count.GetType();
//throw new Exception("Bug in MD5Managed...");
}
}
static bool CompareBytes(byte[] bytes1, byte[] bytes2)
{
for (int idx = 0; idx < bytes1.Length; idx++)
{
if (bytes1[idx] != bytes2[idx])
return false;
}
return true;
}
}
#endif
}
#endif

View File

@@ -0,0 +1,137 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
// ReSharper disable InconsistentNaming
namespace PdfSharp.Pdf.Security
{
/// <summary>
/// Represents the base of all security handlers.
/// </summary>
public abstract class PdfSecurityHandler : PdfDictionary
{
internal PdfSecurityHandler(PdfDocument document)
: base(document)
{ }
internal PdfSecurityHandler(PdfDictionary dict)
: base(dict)
{ }
/// <summary>
/// Predefined keys of this dictionary.
/// </summary>
internal class Keys : KeysBase
{
/// <summary>
/// (Required) The name of the preferred security handler for this document. Typically,
/// it is the name of the security handler that was used to encrypt the document. If
/// SubFilter is not present, only this security handler should be used when opening
/// the document. If it is present, consumer applications can use any security handler
/// that implements the format specified by SubFilter.
/// Standard is the name of the built-in password-based security handler. Names for other
/// security handlers can be registered by using the procedure described in Appendix E.
/// </summary>
[KeyInfo(KeyType.Name | KeyType.Required)]
public const string Filter = "/Filter";
/// <summary>
/// (Optional; PDF 1.3) A name that completely specifies the format and interpretation of
/// the contents of the encryption dictionary. It is needed to allow security handlers other
/// than the one specified by Filter to decrypt the document. If this entry is absent, other
/// security handlers should not be allowed to decrypt the document.
/// </summary>
[KeyInfo("1.3", KeyType.Name | KeyType.Optional)]
public const string SubFilter = "/SubFilter";
/// <summary>
/// (Optional but strongly recommended) A code specifying the algorithm to be used in encrypting
/// and decrypting the document:
/// 0 An algorithm that is undocumented and no longer supported, and whose use is strongly discouraged.
/// 1 Algorithm 3.1, with an encryption key length of 40 bits.
/// 2 (PDF 1.4) Algorithm 3.1, but permitting encryption key lengths greater than 40 bits.
/// 3 (PDF 1.4) An unpublished algorithm that permits encryption key lengths ranging from 40 to 128 bits.
/// 4 (PDF 1.5) The security handler defines the use of encryption and decryption in the document, using
/// the rules specified by the CF, StmF, and StrF entries.
/// The default value if this entry is omitted is 0, but a value of 1 or greater is strongly recommended.
/// </summary>
[KeyInfo(KeyType.Integer | KeyType.Optional)]
public const string V = "/V";
/// <summary>
/// (Optional; PDF 1.4; only if V is 2 or 3) The length of the encryption key, in bits.
/// The value must be a multiple of 8, in the range 40 to 128. Default value: 40.
/// </summary>
[KeyInfo("1.4", KeyType.Integer | KeyType.Optional)]
public const string Length = "/Length";
/// <summary>
/// (Optional; meaningful only when the value of V is 4; PDF 1.5)
/// A dictionary whose keys are crypt filter names and whose values are the corresponding
/// crypt filter dictionaries. Every crypt filter used in the document must have an entry
/// in this dictionary, except for the standard crypt filter names.
/// </summary>
[KeyInfo(KeyType.Dictionary | KeyType.Optional)]
public const string CF = "/CF";
/// <summary>
/// (Optional; meaningful only when the value of V is 4; PDF 1.5)
/// The name of the crypt filter that is used by default when decrypting streams.
/// The name must be a key in the CF dictionary or a standard crypt filter name. All streams
/// in the document, except for cross-reference streams or streams that have a Crypt entry in
/// their Filter array, are decrypted by the security handler, using this crypt filter.
/// Default value: Identity.
/// </summary>
[KeyInfo("1.5", KeyType.Name | KeyType.Optional)]
public const string StmF = "/StmF";
/// <summary>
/// (Optional; meaningful only when the value of V is 4; PDF 1.)
/// The name of the crypt filter that is used when decrypting all strings in the document.
/// The name must be a key in the CF dictionary or a standard crypt filter name.
/// Default value: Identity.
/// </summary>
[KeyInfo("1.5", KeyType.Name | KeyType.Optional)]
public const string StrF = "/StrF";
/// <summary>
/// (Optional; meaningful only when the value of V is 4; PDF 1.6)
/// The name of the crypt filter that should be used by default when encrypting embedded
/// file streams; it must correspond to a key in the CF dictionary or a standard crypt
/// filter name. This entry is provided by the security handler. Applications should respect
/// this value when encrypting embedded files, except for embedded file streams that have
/// their own crypt filter specifier. If this entry is not present, and the embedded file
/// stream does not contain a crypt filter specifier, the stream should be encrypted using
/// the default stream crypt filter specified by StmF.
/// </summary>
[KeyInfo("1.6", KeyType.Name | KeyType.Optional)]
public const string EFF = "/EFF";
}
}
}

View File

@@ -0,0 +1,253 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
namespace PdfSharp.Pdf.Security
{
/// <summary>
/// Encapsulates access to the security settings of a PDF document.
/// </summary>
public sealed class PdfSecuritySettings
{
internal PdfSecuritySettings(PdfDocument document)
{
_document = document;
}
readonly PdfDocument _document;
/// <summary>
/// Indicates whether the granted access to the document is 'owner permission'. Returns true if the document
/// is unprotected or was opened with the owner password. Returns false if the document was opened with the
/// user password.
/// </summary>
public bool HasOwnerPermissions
{
get { return _hasOwnerPermissions; }
}
internal bool _hasOwnerPermissions = true;
/// <summary>
/// Gets or sets the document security level. If you set the security level to anything but PdfDocumentSecurityLevel.None
/// you must also set a user and/or an owner password. Otherwise saving the document will fail.
/// </summary>
public PdfDocumentSecurityLevel DocumentSecurityLevel
{
get { return _documentSecurityLevel; }
set { _documentSecurityLevel = value; }
}
PdfDocumentSecurityLevel _documentSecurityLevel;
/// <summary>
/// Sets the user password of the document. Setting a password automatically sets the
/// PdfDocumentSecurityLevel to PdfDocumentSecurityLevel.Encrypted128Bit if its current
/// value is PdfDocumentSecurityLevel.None.
/// </summary>
public string UserPassword
{
set { SecurityHandler.UserPassword = value; }
}
/// <summary>
/// Sets the owner password of the document. Setting a password automatically sets the
/// PdfDocumentSecurityLevel to PdfDocumentSecurityLevel.Encrypted128Bit if its current
/// value is PdfDocumentSecurityLevel.None.
/// </summary>
public string OwnerPassword
{
set { SecurityHandler.OwnerPassword = value; }
}
/// <summary>
/// Determines whether the document can be saved.
/// </summary>
internal bool CanSave(ref string message)
{
if (_documentSecurityLevel != PdfDocumentSecurityLevel.None)
{
if (String.IsNullOrEmpty(SecurityHandler._userPassword) && String.IsNullOrEmpty(SecurityHandler._ownerPassword))
{
message = PSSR.UserOrOwnerPasswordRequired;
return false;
}
}
return true;
}
#region Permissions
//TODO: Use documentation from our English Acrobat 6.0 version.
/// <summary>
/// Permits printing the document. Should be used in conjunction with PermitFullQualityPrint.
/// </summary>
public bool PermitPrint
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitPrint) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitPrint;
else
permission &= ~PdfUserAccessPermission.PermitPrint;
SecurityHandler.Permission = permission;
}
}
/// <summary>
/// Permits modifying the document.
/// </summary>
public bool PermitModifyDocument
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitModifyDocument) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitModifyDocument;
else
permission &= ~PdfUserAccessPermission.PermitModifyDocument;
SecurityHandler.Permission = permission;
}
}
/// <summary>
/// Permits content copying or extraction.
/// </summary>
public bool PermitExtractContent
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitExtractContent) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitExtractContent;
else
permission &= ~PdfUserAccessPermission.PermitExtractContent;
SecurityHandler.Permission = permission;
}
}
/// <summary>
/// Permits commenting the document.
/// </summary>
public bool PermitAnnotations
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitAnnotations) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitAnnotations;
else
permission &= ~PdfUserAccessPermission.PermitAnnotations;
SecurityHandler.Permission = permission;
}
}
/// <summary>
/// Permits filling of form fields.
/// </summary>
public bool PermitFormsFill
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitFormsFill) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitFormsFill;
else
permission &= ~PdfUserAccessPermission.PermitFormsFill;
SecurityHandler.Permission = permission;
}
}
/// <summary>
/// Permits content extraction for accessibility.
/// </summary>
public bool PermitAccessibilityExtractContent
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitAccessibilityExtractContent) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitAccessibilityExtractContent;
else
permission &= ~PdfUserAccessPermission.PermitAccessibilityExtractContent;
SecurityHandler.Permission = permission;
}
}
/// <summary>
/// Permits to insert, rotate, or delete pages and create bookmarks or thumbnail images even if
/// PermitModifyDocument is not set.
/// </summary>
public bool PermitAssembleDocument
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitAssembleDocument) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitAssembleDocument;
else
permission &= ~PdfUserAccessPermission.PermitAssembleDocument;
SecurityHandler.Permission = permission;
}
}
/// <summary>
/// Permits to print in high quality. insert, rotate, or delete pages and create bookmarks or thumbnail images
/// even if PermitModifyDocument is not set.
/// </summary>
public bool PermitFullQualityPrint
{
get { return (SecurityHandler.Permission & PdfUserAccessPermission.PermitFullQualityPrint) != 0; }
set
{
PdfUserAccessPermission permission = SecurityHandler.Permission;
if (value)
permission |= PdfUserAccessPermission.PermitFullQualityPrint;
else
permission &= ~PdfUserAccessPermission.PermitFullQualityPrint;
SecurityHandler.Permission = permission;
}
}
#endregion
/// <summary>
/// PdfStandardSecurityHandler is the only implemented handler.
/// </summary>
internal PdfStandardSecurityHandler SecurityHandler
{
get { return _document._trailer.SecurityHandler; }
}
}
}

View File

@@ -0,0 +1,737 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
using PdfSharp.Pdf.Advanced;
using PdfSharp.Pdf.Internal;
#if !NETFX_CORE && !UWP
using System.Security.Cryptography;
#endif
#pragma warning disable 0169
#pragma warning disable 0649
namespace PdfSharp.Pdf.Security
{
/// <summary>
/// Represents the standard PDF security handler.
/// </summary>
public sealed class PdfStandardSecurityHandler : PdfSecurityHandler
{
internal PdfStandardSecurityHandler(PdfDocument document)
: base(document)
{ }
internal PdfStandardSecurityHandler(PdfDictionary dict)
: base(dict)
{ }
/// <summary>
/// Sets the user password of the document. Setting a password automatically sets the
/// PdfDocumentSecurityLevel to PdfDocumentSecurityLevel.Encrypted128Bit if its current
/// value is PdfDocumentSecurityLevel.None.
/// </summary>
public string UserPassword
{
set
{
if (_document._securitySettings.DocumentSecurityLevel == PdfDocumentSecurityLevel.None)
_document._securitySettings.DocumentSecurityLevel = PdfDocumentSecurityLevel.Encrypted128Bit;
_userPassword = value;
}
}
internal string _userPassword;
/// <summary>
/// Sets the owner password of the document. Setting a password automatically sets the
/// PdfDocumentSecurityLevel to PdfDocumentSecurityLevel.Encrypted128Bit if its current
/// value is PdfDocumentSecurityLevel.None.
/// </summary>
public string OwnerPassword
{
set
{
if (_document._securitySettings.DocumentSecurityLevel == PdfDocumentSecurityLevel.None)
_document._securitySettings.DocumentSecurityLevel = PdfDocumentSecurityLevel.Encrypted128Bit;
_ownerPassword = value;
}
}
internal string _ownerPassword;
/// <summary>
/// Gets or sets the user access permission represented as an integer in the P key.
/// </summary>
internal PdfUserAccessPermission Permission
{
get
{
PdfUserAccessPermission permission = (PdfUserAccessPermission)Elements.GetInteger(Keys.P);
if ((int)permission == 0)
permission = PdfUserAccessPermission.PermitAll;
return permission;
}
set { Elements.SetInteger(Keys.P, (int)value); }
}
/// <summary>
/// Encrypts the whole document.
/// </summary>
public void EncryptDocument()
{
foreach (PdfReference iref in _document._irefTable.AllReferences)
{
if (!ReferenceEquals(iref.Value, this))
EncryptObject(iref.Value);
}
}
/// <summary>
/// Encrypts an indirect object.
/// </summary>
internal void EncryptObject(PdfObject value)
{
Debug.Assert(value.Reference != null);
SetHashKey(value.ObjectID);
#if DEBUG
if (value.ObjectID.ObjectNumber == 10)
GetType();
#endif
PdfDictionary dict;
PdfArray array;
PdfStringObject str;
if ((dict = value as PdfDictionary) != null)
EncryptDictionary(dict);
else if ((array = value as PdfArray) != null)
EncryptArray(array);
else if ((str = value as PdfStringObject) != null)
{
if (str.Length != 0)
{
byte[] bytes = str.EncryptionValue;
PrepareKey();
EncryptRC4(bytes);
str.EncryptionValue = bytes;
}
}
}
/// <summary>
/// Encrypts a dictionary.
/// </summary>
void EncryptDictionary(PdfDictionary dict)
{
PdfName[] names = dict.Elements.KeyNames;
foreach (KeyValuePair<string, PdfItem> item in dict.Elements)
{
PdfString value1;
PdfDictionary value2;
PdfArray value3;
if ((value1 = item.Value as PdfString) != null)
EncryptString(value1);
else if ((value2 = item.Value as PdfDictionary) != null)
EncryptDictionary(value2);
else if ((value3 = item.Value as PdfArray) != null)
EncryptArray(value3);
}
if (dict.Stream != null)
{
byte[] bytes = dict.Stream.Value;
if (bytes.Length != 0)
{
PrepareKey();
EncryptRC4(bytes);
dict.Stream.Value = bytes;
}
}
}
/// <summary>
/// Encrypts an array.
/// </summary>
void EncryptArray(PdfArray array)
{
int count = array.Elements.Count;
for (int idx = 0; idx < count; idx++)
{
PdfItem item = array.Elements[idx];
PdfString value1;
PdfDictionary value2;
PdfArray value3;
if ((value1 = item as PdfString) != null)
EncryptString(value1);
else if ((value2 = item as PdfDictionary) != null)
EncryptDictionary(value2);
else if ((value3 = item as PdfArray) != null)
EncryptArray(value3);
}
}
/// <summary>
/// Encrypts a string.
/// </summary>
void EncryptString(PdfString value)
{
if (value.Length != 0)
{
byte[] bytes = value.EncryptionValue;
PrepareKey();
EncryptRC4(bytes);
value.EncryptionValue = bytes;
}
}
/// <summary>
/// Encrypts an array.
/// </summary>
internal byte[] EncryptBytes(byte[] bytes)
{
if (bytes != null && bytes.Length != 0)
{
PrepareKey();
EncryptRC4(bytes);
}
return bytes;
}
#region Encryption Algorithms
/// <summary>
/// Checks the password.
/// </summary>
/// <param name="inputPassword">Password or null if no password is provided.</param>
public PasswordValidity ValidatePassword(string inputPassword)
{
// We can handle 40 and 128 bit standard encryption.
string filter = Elements.GetName(PdfSecurityHandler.Keys.Filter);
int v = Elements.GetInteger(PdfSecurityHandler.Keys.V);
if (filter != "/Standard" || !(v >= 1 && v <= 3))
throw new PdfReaderException(PSSR.UnknownEncryption);
byte[] documentID = PdfEncoders.RawEncoding.GetBytes(Owner.Internals.FirstDocumentID);
byte[] oValue = PdfEncoders.RawEncoding.GetBytes(Elements.GetString(Keys.O));
byte[] uValue = PdfEncoders.RawEncoding.GetBytes(Elements.GetString(Keys.U));
int pValue = Elements.GetInteger(Keys.P);
int rValue = Elements.GetInteger(Keys.R);
if (inputPassword == null)
inputPassword = "";
bool strongEncryption = rValue == 3;
int keyLength = strongEncryption ? 16 : 32;
// Try owner password first.
//byte[] password = PdfEncoders.RawEncoding.GetBytes(inputPassword);
InitWithOwnerPassword(documentID, inputPassword, oValue, pValue, strongEncryption);
if (EqualsKey(uValue, keyLength))
{
_document.SecuritySettings._hasOwnerPermissions = true;
return PasswordValidity.OwnerPassword;
}
_document.SecuritySettings._hasOwnerPermissions = false;
// Now try user password.
//password = PdfEncoders.RawEncoding.GetBytes(inputPassword);
InitWithUserPassword(documentID, inputPassword, oValue, pValue, strongEncryption);
if (EqualsKey(uValue, keyLength))
return PasswordValidity.UserPassword;
return PasswordValidity.Invalid;
}
[Conditional("DEBUG")]
static void DumpBytes(string tag, byte[] bytes)
{
string dump = tag + ": ";
for (int idx = 0; idx < bytes.Length; idx++)
dump += String.Format("{0:X2}", bytes[idx]);
Debug.WriteLine(dump);
}
/// <summary>
/// Pads a password to a 32 byte array.
/// </summary>
static byte[] PadPassword(string password)
{
byte[] padded = new byte[32];
if (password == null)
Array.Copy(PasswordPadding, 0, padded, 0, 32);
else
{
int length = password.Length;
Array.Copy(PdfEncoders.RawEncoding.GetBytes(password), 0, padded, 0, Math.Min(length, 32));
if (length < 32)
Array.Copy(PasswordPadding, 0, padded, length, 32 - length);
}
return padded;
}
static readonly byte[] PasswordPadding = // 32 bytes password padding defined by Adobe
{
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,
};
/// <summary>
/// Generates the user key based on the padded user password.
/// </summary>
void InitWithUserPassword(byte[] documentID, string userPassword, byte[] ownerKey, int permissions, bool strongEncryption)
{
InitEncryptionKey(documentID, PadPassword(userPassword), ownerKey, permissions, strongEncryption);
SetupUserKey(documentID);
}
/// <summary>
/// Generates the user key based on the padded owner password.
/// </summary>
void InitWithOwnerPassword(byte[] documentID, string ownerPassword, byte[] ownerKey, int permissions, bool strongEncryption)
{
byte[] userPad = ComputeOwnerKey(ownerKey, PadPassword(ownerPassword), strongEncryption);
InitEncryptionKey(documentID, userPad, ownerKey, permissions, strongEncryption);
SetupUserKey(documentID);
}
/// <summary>
/// Computes the padded user password from the padded owner password.
/// </summary>
byte[] ComputeOwnerKey(byte[] userPad, byte[] ownerPad, bool strongEncryption)
{
byte[] ownerKey = new byte[32];
//#if !SILVERLIGHT
byte[] digest = _md5.ComputeHash(ownerPad);
if (strongEncryption)
{
byte[] mkey = new byte[16];
// Hash the pad 50 times
for (int idx = 0; idx < 50; idx++)
digest = _md5.ComputeHash(digest);
Array.Copy(userPad, 0, ownerKey, 0, 32);
// Encrypt the key
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < mkey.Length; ++j)
mkey[j] = (byte)(digest[j] ^ i);
PrepareRC4Key(mkey);
EncryptRC4(ownerKey);
}
}
else
{
PrepareRC4Key(digest, 0, 5);
EncryptRC4(userPad, ownerKey);
}
//#endif
return ownerKey;
}
/// <summary>
/// Computes the encryption key.
/// </summary>
void InitEncryptionKey(byte[] documentID, byte[] userPad, byte[] ownerKey, int permissions, bool strongEncryption)
{
//#if !SILVERLIGHT
_ownerKey = ownerKey;
_encryptionKey = new byte[strongEncryption ? 16 : 5];
#if !NETFX_CORE
_md5.Initialize();
_md5.TransformBlock(userPad, 0, userPad.Length, userPad, 0);
_md5.TransformBlock(ownerKey, 0, ownerKey.Length, ownerKey, 0);
// Split permission into 4 bytes
byte[] permission = new byte[4];
permission[0] = (byte)permissions;
permission[1] = (byte)(permissions >> 8);
permission[2] = (byte)(permissions >> 16);
permission[3] = (byte)(permissions >> 24);
_md5.TransformBlock(permission, 0, 4, permission, 0);
_md5.TransformBlock(documentID, 0, documentID.Length, documentID, 0);
_md5.TransformFinalBlock(permission, 0, 0);
byte[] digest = _md5.Hash;
_md5.Initialize();
// Create the hash 50 times (only for 128 bit)
if (_encryptionKey.Length == 16)
{
for (int idx = 0; idx < 50; idx++)
{
digest = _md5.ComputeHash(digest);
_md5.Initialize();
}
}
Array.Copy(digest, 0, _encryptionKey, 0, _encryptionKey.Length);
//#endif
#endif
}
/// <summary>
/// Computes the user key.
/// </summary>
void SetupUserKey(byte[] documentID)
{
#if !NETFX_CORE
//#if !SILVERLIGHT
if (_encryptionKey.Length == 16)
{
_md5.TransformBlock(PasswordPadding, 0, PasswordPadding.Length, PasswordPadding, 0);
_md5.TransformFinalBlock(documentID, 0, documentID.Length);
byte[] digest = _md5.Hash;
_md5.Initialize();
Array.Copy(digest, 0, _userKey, 0, 16);
for (int idx = 16; idx < 32; idx++)
_userKey[idx] = 0;
//Encrypt the key
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < _encryptionKey.Length; j++)
digest[j] = (byte)(_encryptionKey[j] ^ i);
PrepareRC4Key(digest, 0, _encryptionKey.Length);
EncryptRC4(_userKey, 0, 16);
}
}
else
{
PrepareRC4Key(_encryptionKey);
EncryptRC4(PasswordPadding, _userKey);
}
//#endif
#endif
}
/// <summary>
/// Prepare the encryption key.
/// </summary>
void PrepareKey()
{
if (_key != null && _keySize > 0) //!!!mod 2017-11-06 Added "if" because PrepareRC4Key fails if _key is null. But _key appears to be always null, so maybe PrepareKey() is obsolete.
PrepareRC4Key(_key, 0, _keySize);
}
/// <summary>
/// Prepare the encryption key.
/// </summary>
void PrepareRC4Key(byte[] key)
{
PrepareRC4Key(key, 0, key.Length);
}
/// <summary>
/// Prepare the encryption key.
/// </summary>
void PrepareRC4Key(byte[] key, int offset, int length)
{
int idx1 = 0;
int idx2 = 0;
for (int idx = 0; idx < 256; idx++)
_state[idx] = (byte)idx;
byte tmp;
for (int idx = 0; idx < 256; idx++)
{
idx2 = (key[idx1 + offset] + _state[idx] + idx2) & 255;
tmp = _state[idx];
_state[idx] = _state[idx2];
_state[idx2] = tmp;
idx1 = (idx1 + 1) % length;
}
}
/// <summary>
/// Encrypts the data.
/// </summary>
// ReSharper disable InconsistentNaming
void EncryptRC4(byte[] data)
// ReSharper restore InconsistentNaming
{
EncryptRC4(data, 0, data.Length, data);
}
/// <summary>
/// Encrypts the data.
/// </summary>
// ReSharper disable InconsistentNaming
void EncryptRC4(byte[] data, int offset, int length)
// ReSharper restore InconsistentNaming
{
EncryptRC4(data, offset, length, data);
}
/// <summary>
/// Encrypts the data.
/// </summary>
void EncryptRC4(byte[] inputData, byte[] outputData)
{
EncryptRC4(inputData, 0, inputData.Length, outputData);
}
/// <summary>
/// Encrypts the data.
/// </summary>
void EncryptRC4(byte[] inputData, int offset, int length, byte[] outputData)
{
length += offset;
int x = 0, y = 0;
byte b;
for (int idx = offset; idx < length; idx++)
{
x = (x + 1) & 255;
y = (_state[x] + y) & 255;
b = _state[x];
_state[x] = _state[y];
_state[y] = b;
outputData[idx] = (byte)(inputData[idx] ^ _state[(_state[x] + _state[y]) & 255]);
}
}
/// <summary>
/// Checks whether the calculated key correct.
/// </summary>
bool EqualsKey(byte[] value, int length)
{
for (int idx = 0; idx < length; idx++)
{
if (_userKey[idx] != value[idx])
return false;
}
return true;
}
/// <summary>
/// Set the hash key for the specified object.
/// </summary>
internal void SetHashKey(PdfObjectID id)
{
#if !NETFX_CORE
//#if !SILVERLIGHT
byte[] objectId = new byte[5];
_md5.Initialize();
// Split the object number and generation
objectId[0] = (byte)id.ObjectNumber;
objectId[1] = (byte)(id.ObjectNumber >> 8);
objectId[2] = (byte)(id.ObjectNumber >> 16);
objectId[3] = (byte)id.GenerationNumber;
objectId[4] = (byte)(id.GenerationNumber >> 8);
_md5.TransformBlock(_encryptionKey, 0, _encryptionKey.Length, _encryptionKey, 0);
_md5.TransformFinalBlock(objectId, 0, objectId.Length);
_key = _md5.Hash;
_md5.Initialize();
_keySize = _encryptionKey.Length + 5;
if (_keySize > 16)
_keySize = 16;
//#endif
#endif
}
/// <summary>
/// Prepares the security handler for encrypting the document.
/// </summary>
public void PrepareEncryption()
{
//#if !SILVERLIGHT
Debug.Assert(_document._securitySettings.DocumentSecurityLevel != PdfDocumentSecurityLevel.None);
int permissions = (int)Permission;
bool strongEncryption = _document._securitySettings.DocumentSecurityLevel == PdfDocumentSecurityLevel.Encrypted128Bit;
PdfInteger vValue;
PdfInteger length;
PdfInteger rValue;
if (strongEncryption)
{
vValue = new PdfInteger(2);
length = new PdfInteger(128);
rValue = new PdfInteger(3);
}
else
{
vValue = new PdfInteger(1);
length = new PdfInteger(40);
rValue = new PdfInteger(2);
}
if (String.IsNullOrEmpty(_userPassword))
_userPassword = "";
// Use user password twice if no owner password provided.
if (String.IsNullOrEmpty(_ownerPassword))
_ownerPassword = _userPassword;
// Correct permission bits
permissions |= (int)(strongEncryption ? (uint)0xfffff0c0 : (uint)0xffffffc0);
permissions &= unchecked((int)0xfffffffc);
PdfInteger pValue = new PdfInteger(permissions);
Debug.Assert(_ownerPassword.Length > 0, "Empty owner password.");
byte[] userPad = PadPassword(_userPassword);
byte[] ownerPad = PadPassword(_ownerPassword);
_md5.Initialize();
_ownerKey = ComputeOwnerKey(userPad, ownerPad, strongEncryption);
byte[] documentID = PdfEncoders.RawEncoding.GetBytes(_document.Internals.FirstDocumentID);
InitWithUserPassword(documentID, _userPassword, _ownerKey, permissions, strongEncryption);
PdfString oValue = new PdfString(PdfEncoders.RawEncoding.GetString(_ownerKey, 0, _ownerKey.Length));
PdfString uValue = new PdfString(PdfEncoders.RawEncoding.GetString(_userKey, 0, _userKey.Length));
Elements[Keys.Filter] = new PdfName("/Standard");
Elements[Keys.V] = vValue;
Elements[Keys.Length] = length;
Elements[Keys.R] = rValue;
Elements[Keys.O] = oValue;
Elements[Keys.U] = uValue;
Elements[Keys.P] = pValue;
//#endif
}
/// <summary>
/// The global encryption key.
/// </summary>
byte[] _encryptionKey;
#if !SILVERLIGHT && !UWP
/// <summary>
/// The message digest algorithm MD5.
/// </summary>
readonly MD5 _md5 = new MD5CryptoServiceProvider();
#if DEBUG_
readonly MD5Managed _md5M = new MD5Managed();
#endif
#else
readonly MD5Managed _md5 = new MD5Managed();
#endif
#if NETFX_CORE
// readonly MD5Managed _md5 = new MD5Managed();
#endif
/// <summary>
/// Bytes used for RC4 encryption.
/// </summary>
readonly byte[] _state = new byte[256];
/// <summary>
/// The encryption key for the owner.
/// </summary>
byte[] _ownerKey = new byte[32];
/// <summary>
/// The encryption key for the user.
/// </summary>
readonly byte[] _userKey = new byte[32];
/// <summary>
/// The encryption key for a particular object/generation.
/// </summary>
byte[] _key;
/// <summary>
/// The encryption key length for a particular object/generation.
/// </summary>
int _keySize;
#endregion
internal override void WriteObject(PdfWriter writer)
{
// Don't encrypt myself.
PdfStandardSecurityHandler securityHandler = writer.SecurityHandler;
writer.SecurityHandler = null;
base.WriteObject(writer);
writer.SecurityHandler = securityHandler;
}
#region Keys
/// <summary>
/// Predefined keys of this dictionary.
/// </summary>
internal sealed new class Keys : PdfSecurityHandler.Keys
{
/// <summary>
/// (Required) A number specifying which revision of the standard security handler
/// should be used to interpret this dictionary:
/// <20> 2 if the document is encrypted with a V value less than 2 and does not have any of
/// the access permissions set (by means of the P entry, below) that are designated
/// "Revision 3 or greater".
/// <20> 3 if the document is encrypted with a V value of 2 or 3, or has any "Revision 3 or
/// greater" access permissions set.
/// <20> 4 if the document is encrypted with a V value of 4
/// </summary>
[KeyInfo(KeyType.Integer | KeyType.Required)]
public const string R = "/R";
/// <summary>
/// (Required) A 32-byte string, based on both the owner and user passwords, that is
/// used in computing the encryption key and in determining whether a valid owner
/// password was entered.
/// </summary>
[KeyInfo(KeyType.String | KeyType.Required)]
public const string O = "/O";
/// <summary>
/// (Required) A 32-byte string, based on the user password, that is used in determining
/// whether to prompt the user for a password and, if so, whether a valid user or owner
/// password was entered.
/// </summary>
[KeyInfo(KeyType.String | KeyType.Required)]
public const string U = "/U";
/// <summary>
/// (Required) A set of flags specifying which operations are permitted when the document
/// is opened with user access.
/// </summary>
[KeyInfo(KeyType.Integer | KeyType.Required)]
public const string P = "/P";
/// <summary>
/// (Optional; meaningful only when the value of V is 4; PDF 1.5) Indicates whether
/// the document-level metadata stream is to be encrypted. Applications should respect this value.
/// Default value: true.
/// </summary>
[KeyInfo(KeyType.Boolean | KeyType.Optional)]
public const string EncryptMetadata = "/EncryptMetadata";
/// <summary>
/// Gets the KeysMeta for these keys.
/// </summary>
public static DictionaryMeta Meta
{
get { return _meta ?? (_meta = CreateMeta(typeof(Keys))); }
}
static DictionaryMeta _meta;
}
/// <summary>
/// Gets the KeysMeta of this dictionary type.
/// </summary>
internal override DictionaryMeta Meta
{
get { return Keys.Meta; }
}
#endregion
}
}

View File

@@ -0,0 +1,53 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
namespace PdfSharp.Pdf.Security
{
/// <summary>
/// Specifies the security level of the PDF document.
/// </summary>
public enum PdfDocumentSecurityLevel
{
/// <summary>
/// Document is not protected.
/// </summary>
None,
/// <summary>
/// Document is protected with 40-bit security. This option is for compatibility with
/// Acrobat 3 and 4 only. Use Encrypted128Bit whenever possible.
/// </summary>
Encrypted40Bit,
/// <summary>
/// Document is protected with 128-bit security.
/// </summary>
Encrypted128Bit,
}
}

View File

@@ -0,0 +1,92 @@
#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
namespace PdfSharp.Pdf.Security
{
/// <summary>
/// Specifies which operations are permitted when the document is opened with user access.
/// </summary>
[Flags]
internal enum PdfUserAccessPermission
{
/// <summary>
/// Permits everything. This is the default value.
/// </summary>
PermitAll = -3, // = 0xFFFFFFFC,
// Bit 1<>2 Reserved; must be 0.
// Bit 3 (Revision 2) Print the document.
// (Revision 3 or greater) Print the document (possibly not at the highest
// quality level, depending on whether bit 12 is also set).
PermitPrint = 0x00000004, //1 << (3 - 1),
// Bit 4 Modify the contents of the document by operations other than
// those controlled by bits 6, 9, and 11.
PermitModifyDocument = 0x00000008, //1 << (4 - 1),
// Bit 5 (Revision 2) Copy or otherwise extract text and graphics from the
// document, including extracting text and graphics (in support of accessibility
// to users with disabilities or for other purposes).
// (Revision 3 or greater) Copy or otherwise extract text and graphics
// from the document by operations other than that controlled by bit 10.
PermitExtractContent = 0x00000010, //1 << (5 - 1),
// Bit 6 Add or modify text annotations, fill in interactive form fields, and,
// if bit 4 is also set, create or modify interactive form fields (including
// signature fields).
PermitAnnotations = 0x00000020, //1 << (6 - 1),
// Bit 7<>8 Reserved; must be 1.
// 9 (Revision 3 or greater) Fill in existing interactive form fields (including
// signature fields), even if bit 6 is clear.
PermitFormsFill = 0x00000100, //1 << (9 - 1),
// Bit 10 (Revision 3 or greater) Extract text and graphics (in support of accessibility
// to users with disabilities or for other purposes).
PermitAccessibilityExtractContent = 0x00000200, //1 << (10 - 1),
// Bit 11 (Revision 3 or greater) Assemble the document (insert, rotate, or delete
// pages and create bookmarks or thumbnail images), even if bit 4
// is clear.
PermitAssembleDocument = 0x00000400, //1 << (11 - 1),
// Bit 12 (Revision 3 or greater) Print the document to a representation from
// which a faithful digital copy of the PDF content could be generated.
// When this bit is clear (and bit 3 is set), printing is limited to a lowlevel
// representation of the appearance, possibly of degraded quality.
// (See implementation note 24 in Appendix H.)
PermitFullQualityPrint = 0x00000800, //1 << (12 - 1),
//Bit 13<31>32 (Revision 3 or greater) Reserved; must be 1.
}
}