First commit
Send all results
This commit is contained in:
426
PdfSharp/Pdf.Security/MD5Managed.cs
Normal file
426
PdfSharp/Pdf.Security/MD5Managed.cs
Normal 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
|
137
PdfSharp/Pdf.Security/PdfSecurityHandler.cs
Normal file
137
PdfSharp/Pdf.Security/PdfSecurityHandler.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
253
PdfSharp/Pdf.Security/PdfSecuritySettings.cs
Normal file
253
PdfSharp/Pdf.Security/PdfSecuritySettings.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
737
PdfSharp/Pdf.Security/PdfStandardSecurityHandler.cs
Normal file
737
PdfSharp/Pdf.Security/PdfStandardSecurityHandler.cs
Normal 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
|
||||
}
|
||||
}
|
53
PdfSharp/Pdf.Security/enums/PdfDocumentSecurity.cs
Normal file
53
PdfSharp/Pdf.Security/enums/PdfDocumentSecurity.cs
Normal 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,
|
||||
}
|
||||
}
|
92
PdfSharp/Pdf.Security/enums/PdfUserAccessPermission.cs
Normal file
92
PdfSharp/Pdf.Security/enums/PdfUserAccessPermission.cs
Normal 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.
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user