mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-22 20:13:58 +08:00
verify password against user password or throw
This commit is contained in:
@@ -19,6 +19,10 @@
|
||||
|
||||
public string UserPasswordCheck { get; }
|
||||
|
||||
public byte[] OwnerBytes { get; }
|
||||
|
||||
public byte[] UserBytes { get; }
|
||||
|
||||
public UserAccessPermissions UserAccessPermissions { get; }
|
||||
|
||||
public bool IsStandardFilter => string.Equals(Filter, "Standard", StringComparison.OrdinalIgnoreCase);
|
||||
@@ -45,6 +49,9 @@
|
||||
UserAccessPermissions = userAccessPermissions;
|
||||
Dictionary = dictionary;
|
||||
EncryptMetadata = encryptMetadata;
|
||||
|
||||
OwnerBytes = OtherEncodings.StringAsLatin1Bytes(ownerPasswordCheck);
|
||||
UserBytes = OtherEncodings.StringAsLatin1Bytes(userPasswordCheck);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -46,6 +46,7 @@
|
||||
documentIdBytes = trailerDictionary.Identifier != null && trailerDictionary.Identifier.Count == 2 ?
|
||||
OtherEncodings.StringAsLatin1Bytes(trailerDictionary.Identifier[0])
|
||||
: EmptyArray<byte>.Instance;
|
||||
|
||||
this.password = password ?? string.Empty;
|
||||
|
||||
if (encryptionDictionary == null)
|
||||
@@ -70,12 +71,72 @@
|
||||
? 5
|
||||
: encryptionDictionary.KeyLength.GetValueOrDefault() / 8;
|
||||
|
||||
encryptionKey = CalculateKeyRevisions2To4(passwordBytes, ownerKey, (int)encryptionDictionary.UserAccessPermissions, encryptionDictionary.StandardSecurityHandlerRevision,
|
||||
if (IsUserPassword(passwordBytes, length))
|
||||
{
|
||||
encryptionKey = CalculateKeyRevisions2To4(passwordBytes, ownerKey, (int) encryptionDictionary.UserAccessPermissions, encryptionDictionary.StandardSecurityHandlerRevision,
|
||||
length, documentIdBytes, encryptionDictionary.EncryptMetadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("TODO: check owner password.");
|
||||
}
|
||||
|
||||
useAes = false;
|
||||
}
|
||||
|
||||
private bool IsUserPassword(byte[] passwordBytes, int length)
|
||||
{
|
||||
// 1. Create an encryption key based on the user password string.
|
||||
var password = CalculateKeyRevisions2To4(passwordBytes, encryptionDictionary.OwnerBytes, (int) encryptionDictionary.UserAccessPermissions,
|
||||
encryptionDictionary.StandardSecurityHandlerRevision, length, documentIdBytes, encryptionDictionary.EncryptMetadata);
|
||||
|
||||
byte[] output;
|
||||
|
||||
if (encryptionDictionary.StandardSecurityHandlerRevision >= 3)
|
||||
{
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
// 2. Initialize the MD5 hash function and pass the 32-byte padding string.
|
||||
UpdateMd5(md5, PaddingBytes);
|
||||
|
||||
// 3. Pass the first element of the file identifier array to the hash function and finish the hash.
|
||||
UpdateMd5(md5, documentIdBytes);
|
||||
md5.TransformFinalBlock(EmptyArray<byte>.Instance, 0, 0);
|
||||
|
||||
var result = md5.Hash;
|
||||
|
||||
// 4. Encrypt the 16-byte result of the hash, using an RC4 encryption function with the encryption key from step 1.
|
||||
var temp = RC4.Encrypt(password, result);
|
||||
|
||||
// 5. Do the following 19 times:
|
||||
for (byte i = 1; i <= 19; i++)
|
||||
{
|
||||
// Take the output from the previous invocation of the RC4 function
|
||||
// and pass it as input to a new invocation of the function
|
||||
|
||||
// Use an encryption key generated by taking each byte of the original encryption key (from step 1)
|
||||
// and performing an XOR operation between that byte and the single-byte value of the iteration counter.
|
||||
var key = password.Select(x => (byte)(x ^ i)).ToArray();
|
||||
temp = RC4.Encrypt(key, temp);
|
||||
}
|
||||
|
||||
output = temp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2. Encrypt the 32-byte padding string using an RC4 encryption function with the encryption key from the preceding step.
|
||||
output = RC4.Encrypt(password, PaddingBytes);
|
||||
}
|
||||
|
||||
if (encryptionDictionary.StandardSecurityHandlerRevision >= 3)
|
||||
{
|
||||
return encryptionDictionary.UserBytes.Take(16).SequenceEqual(output.Take(16));
|
||||
}
|
||||
|
||||
return encryptionDictionary.UserBytes.SequenceEqual(output);
|
||||
}
|
||||
|
||||
public IToken Decrypt(IndirectReference reference, IToken token)
|
||||
{
|
||||
if (token == null)
|
||||
|
Reference in New Issue
Block a user