handle non-standard crypt dictionary type and use hex bytes for password #34

using an online tool to encrypt a simple document with aes-128 seems to add the dictionary type cryptalgorithm rather than cryptfilter. i couldn't find any references to cryptalgorithm in the spec or pdfbox but it seems to work ok when treated as equivalent to cryptfilter.

there are situations where the string derived from a hex token has a different length to the underlying bytes, for example if the hex token contains the '\0' byte, the encryption algorithm needs to use the raw bytes rather than the 'stringified' bytes. this change passes raw bytes for hex tokens for both the user and owner password keys.
This commit is contained in:
Eliot Jones
2019-06-23 13:12:47 +01:00
parent d259f89bd9
commit 0f103554fb
4 changed files with 34 additions and 17 deletions

View File

@@ -52,7 +52,7 @@
throw new PdfDocumentEncryptedException($"Could not find named crypt filter {name} for decryption in crypt dictionary: {cryptDictionaryToken}.");
}
if (cryptDictionaryToken.TryGet(NameToken.Type, out NameToken typeName) && typeName != NameToken.CryptFilter)
if (cryptDictionaryToken.TryGet(NameToken.Type, out NameToken typeName) && typeName != NameToken.CryptFilter && typeName != NameToken.CryptAlgorithm)
{
throw new PdfDocumentEncryptedException($"Invalid crypt dictionary type {typeName} for crypt filter {name}: {cryptDictionaryToken}.");
}

View File

@@ -3,7 +3,6 @@
using System;
using Exceptions;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
internal class EncryptionDictionary
@@ -16,10 +15,6 @@
public int Revision { get; }
public string OwnerPasswordCheck { get; }
public string UserPasswordCheck { get; }
public byte[] OwnerBytes { get; }
public byte[] UserBytes { get; }
@@ -47,8 +42,8 @@
public EncryptionDictionary(string filter, EncryptionAlgorithmCode encryptionAlgorithmCode,
int? keyLength,
int revision,
string ownerPasswordCheck,
string userPasswordCheck,
byte[] ownerBytes,
byte[] userBytes,
byte[] ownerEncryptionBytes,
byte[] userEncryptionBytes,
UserAccessPermissions userAccessPermissions,
@@ -59,16 +54,13 @@
EncryptionAlgorithmCode = encryptionAlgorithmCode;
KeyLength = keyLength;
Revision = revision;
OwnerPasswordCheck = ownerPasswordCheck;
UserPasswordCheck = userPasswordCheck;
OwnerBytes = ownerBytes;
UserBytes = userBytes;
OwnerEncryptionBytes = ownerEncryptionBytes;
UserEncryptionBytes = userEncryptionBytes;
UserAccessPermissions = userAccessPermissions;
Dictionary = dictionary;
EncryptMetadata = encryptMetadata;
OwnerBytes = OtherEncodings.StringAsLatin1Bytes(ownerPasswordCheck);
UserBytes = OtherEncodings.StringAsLatin1Bytes(userPasswordCheck);
}
public bool TryGetCryptHandler(out CryptHandler cryptHandler)

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Encryption
{
using System;
using System.Linq;
using Tokenization.Scanner;
using Tokens;
using Util;
@@ -36,9 +37,32 @@
revision = revisionToken.Int;
}
encryptionDictionary.TryGetOptionalStringDirect(NameToken.O, tokenScanner, out var ownerString);
encryptionDictionary.TryGetOptionalStringDirect(NameToken.U, tokenScanner, out var userString);
byte[] ownerBytes = null;
if (encryptionDictionary.TryGet(NameToken.O, out IToken ownerToken))
{
if (ownerToken is StringToken ownerString)
{
ownerBytes = OtherEncodings.StringAsLatin1Bytes(ownerString.Data);
}
else if (ownerToken is HexToken ownerHex)
{
ownerBytes = ownerHex.Bytes.ToArray();
}
}
byte[] userBytes = null;
if (encryptionDictionary.TryGet(NameToken.U, out IToken userToken))
{
if (userToken is StringToken userString)
{
userBytes = OtherEncodings.StringAsLatin1Bytes(userString.Data);
}
else if (userToken is HexToken userHex)
{
userBytes = userHex.Bytes.ToArray();
}
}
var access = default(UserAccessPermissions);
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.P, tokenScanner, out NumericToken accessToken))
@@ -58,7 +82,7 @@
encryptionDictionary.TryGetOptionalTokenDirect(NameToken.EncryptMetaData, tokenScanner, out BooleanToken encryptMetadata);
return new EncryptionDictionary(filter.Data, code, length, revision, ownerString, userString,
return new EncryptionDictionary(filter.Data, code, length, revision, ownerBytes, userBytes,
ownerEncryptionBytes,
userEncryptionBytes,
access,

View File

@@ -127,6 +127,7 @@
public static readonly NameToken Creator = new NameToken("Creator");
public static readonly NameToken CropBox = new NameToken("CropBox");
public static readonly NameToken Crypt = new NameToken("Crypt");
public static readonly NameToken CryptAlgorithm = new NameToken("CryptAlgorithm");
public static readonly NameToken CryptFilter = new NameToken("CryptFilter");
public static readonly NameToken Cs = new NameToken("CS");
// D