C#でカスタムセキュリティハンドラーを使用してデジタル署名を追加
Contents
[
Hide
]
自分のセキュリティハンドラーを作成するには、希望する暗号化アルゴリズムを適用します。 Adobe Acrobatはそのようなファイルを開くことができませんが、Aspose.Pdfを使用して作業できます。 ハンドラーを作成するには、インターフェースを実装する必要があります。
public interface ICustomSecurityHandler
{
string Filter { get; }
string SubFilter { get; }
int Version { get; }
int Revision { get; }
int KeyLength { get; }
byte[] EncryptPermissions(int permissions);
byte[] GetOwnerKey(string userPassword, string ownerPassword);
byte[] GetUserKey(string userPassword);
void Initialize(EncryptionParameters parameters);
byte[] CalculateEncryptionKey(string password);
byte[] Encrypt(byte[] data, int objectNumber, int generation, byte[] key);
byte[] Decrypt(byte[] data, int objectNumber, int generation, byte[] key);
bool IsOwnerPassword(string password);
bool IsUserPassword(string password);
}
インターフェースの簡単な実装の例(デモ用のみ):
/// <summary>
/// The custom security handler interface.
/// </summary>
class CustomSecurityHandler : ICustomSecurityHandler
{
private EncryptionParameters _parameters;
/// <summary>
/// Gets the filter name.
/// </summary>
public string Filter
{
get
{
return "TestFilter";
}
}
/// <summary>
/// Gets the sub-filter name.
/// </summary>
public string SubFilter
{
get
{
return "TestsSubFilter";
}
}
/// <summary>
/// Gets the handler or encryption algorithm version.
/// </summary>
public int Version
{
get { return 1; }
}
/// <summary>
/// Gets the handler or encryption algorithm revision.
/// </summary>
public int Revision
{
get { return 2; }
}
/// <summary>
/// Gets the key length.
/// </summary>
public int KeyLength
{
get { return 8; }
}
/// <summary>
/// Encrypt the document's permissions field. The result will be written to the Perms encryption dictionary field.
/// When opening a document, the value can be obtained in <see cref="EncryptionParameters"/> via the Perms field.
/// Allows you to check if the document permissions have changed.
/// </summary>
/// <param name="permissions">The document permissions in integer representation.</param>
/// <returns>The encrypted array.</returns>
public byte[] EncryptPermissions(int permissions)
{
byte[] perms = new byte[16];
perms[0] = (byte) (permissions & 0xff);
perms[1] = (byte) ((permissions >> 8) & 0xff);
perms[2] = (byte) ((permissions >> 16) & 0xff);
perms[3] = (byte) ((permissions >> 24) & 0xff);
perms[4] = 0xff;
perms[5] = 0xff;
perms[6] = 0xff;
perms[7] = 0xff;
perms[8] = (byte) 'F';
perms[9] = (byte) 'a';
perms[10] = (byte) 'd';
perms[11] = (byte) 'b';
Random rnd = new Random();
perms[12] = (byte) rnd.Next(0, 0xff);// The random salt for example
perms[13] = (byte) rnd.Next(0, 0xff);// The random salt for example
perms[14] = (byte) rnd.Next(0, 0xff);// The random salt for example
perms[15] = (byte) rnd.Next(0, 0xff);// The random salt for example
for (var index = 0; index < perms.Length; index++)
{
perms[index] ^= 123;
}
return perms;
}
/// <summary>
/// Called to initialize the current instance for encryption.
/// Note that when encrypting, it will be filled with the data of the transferred properties <see cref="ICustomSecurityHandler"/>, and when opening the document from the encryption dictionary.
/// If the method is called during new encryption, then <see cref="EncryptionParameters.UserKey"/> and <see cref="EncryptionParameters.OwnerKey"/> will be null.
/// </summary>
/// <param name="parameters">The encryption parameters.</param>
public void Initialize(EncryptionParameters parameters)
{
_parameters = parameters;
}
/// <summary>
/// Calculate the EncryptionKey. Generally the key is calculated based on the UserKey.
/// You can use values from EncryptionParams, which contains the current parameters at the time of the call.
/// This value is passed as the key argument in <see cref="Encrypt"/> and <see cref="Decrypt"/>.
/// </summary>
/// <param name="password">Password entered by the user.</param>
/// <returns>The array of encryption key.</returns>
public byte[] CalculateEncryptionKey(string password)
{
string userPassword;
if (IsUserPassword(password))
{
userPassword = password;
}
else
{
userPassword = Encoding.UTF8.GetString(GetUserPassword(password));
}
string encKey = userPassword + Encoding.UTF8.GetString(_parameters.OwnerKey) + Encoding.UTF8.GetString(_parameters.UserKey);
byte[] bytes = Encoding.UTF8.GetBytes(encKey);
int sum = 0;
foreach (var b in bytes)
{
sum += b;
}
sum %= 127;
return new byte[] { (byte)sum};
}
/// <summary>
/// Encrypt the data array.
/// </summary>
/// <param name="data">Data to encrypt.</param>
/// <param name="objectNumber">Number of the object containing the encrypted data.</param>
/// <param name="generation">Generation of the object.</param>
/// <param name="key">Key obtained by the CalculateEncryptionKey method</param>
/// <returns>The encrypted data.</returns>
public byte[] Encrypt(byte[] data, int objectNumber, int generation, byte[] key)
{
byte[] result = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
result[i] = (byte)(data[i] ^ key[0]);
}
return result;
}
/// <summary>
/// Decrypt the data array.
/// </summary>
/// <param name="data">Data to decrypt.</param>
/// <param name="objectNumber">Number of the object containing the encrypted data.</param>
/// <param name="generation">Generation of the object.</param>
/// <param name="key">Key obtained by the CalculateEncryptionKey method</param>
/// <returns>The decrypted data.</returns>
public byte[] Decrypt(byte[] data, int objectNumber, int generation, byte[] key)
{
byte[] result = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
result[i] = (byte)(data[i] ^ key[0]);
}
return result;
}
/// <summary>
/// Check if the password is the document owner's password.
/// The method is called after Initialize. The method call is used in the PDF API.
/// </summary>
/// <param name="password">The password.</param>
/// <returns>True, if it is an owner password.</returns>
public bool IsOwnerPassword(string password)
{
// Just for the demonstration.
return !IsUserPassword(password);
}
/// <summary>
/// Check if the password belongs to the user (password for opening the document).
/// The method is called after Initialize. The method call is used in the PDF API.
/// </summary>
/// <param name="password">The password.</param>
/// <returns>True, if it is a password for opening the document.</returns>
public bool IsUserPassword(string password)
{
string u = Encoding.UTF8.GetString(_parameters.UserKey);
// So that an empty password is not determined part of the line.
if (u.Length != 0 && password.Length == 0)
{
return false;
}
return u.Contains(password);
}
/// <summary>
/// Creates an encoded array based on passwords that will be written to the O field of the encryption dictionary.
/// Should only rely on the arguments passed. The user password can be calculated from this field using the owner password.
/// Called during encryption to prepare it and populate the encryption dictionary.
/// The value will be available in <see cref="CalculateEncryptionKey"/> to get the key from the UserKey.
/// The passwords specified by the user when calling document encryption will be passed.
/// Passwords may not be specified or only one may be specified.
/// </summary>
/// <param name="userPassword">The user password.</param>
/// <param name="ownerPassword">The owner password.</param>
/// <returns>The array of owner key.</returns>
public byte[] GetOwnerKey(string userPassword, string ownerPassword)
{
byte[] bytes = Encoding.UTF8.GetBytes(ownerPassword);
int encKeyForUserPass = 0;
foreach (var b in bytes)
{
encKeyForUserPass += b;
}
encKeyForUserPass %= 127;
byte[] userBytes = Encoding.UTF8.GetBytes(userPassword);
for (var index = 0; index < userBytes.Length; index++)
{
userBytes[index] ^= (byte)encKeyForUserPass;
}
return userBytes;
}
/// <summary>
/// Creates an encoded array based on the user's password.
/// This value is typically used to check if the password belongs to the user or owner, and to get the encryption key.
/// Called during encryption to prepare it and populate the encryption dict.
/// The user-specified password is passed as an argument when calling document encryption.
/// </summary>
/// <param name="userPassword">The user password.</param>
/// <returns>The array of user key.</returns>
public byte[] GetUserKey(string userPassword)
{
string userKey = userPassword + "_123";
return Encoding.UTF8.GetBytes(userKey);
}
/// <summary>
/// Extract user password from the owner key.
/// </summary>
/// <param name="ownerPassword">The owner password.</param>
/// <returns>The array of user password.</returns>
private byte[] GetUserPassword(string ownerPassword)
{
byte[] bytes = Encoding.UTF8.GetBytes(ownerPassword);
int encKeyForUserPass = 0;
foreach (var b in bytes)
{
encKeyForUserPass += b;
}
encKeyForUserPass %= 127;
byte[] userPassword = new byte[_parameters.OwnerKey.Length];
for (var index = 0; index < _parameters.OwnerKey.Length; index++)
{
userPassword[index] = (byte)(_parameters.OwnerKey[index] ^ (byte)encKeyForUserPass);
}
return userPassword;
}
}
文書の暗号化の例:
暗号化された文書を開く例: