Blog

All Blog Posts  |  Next Post  |  Previous Post

A quick look at PDF encryption and decryption with TMS Cryptography Pack

Today

TMS Cryptography Pack already dealt with PDF files with PAdES, an ETSI standard to sign PDF with RSA or ECDSA private keys, that inserts signature blocks within documents. These signatures use the Cryptographic Message Syntax (CMS) format, as described in RFC 5652. If valid and generated with trusted certificates/keys, they are recognized by all mainstream PDF readers, such as Acrobat, FoxIT or PDF X-Change.

However, users may also want to programmatically encrypt and decrypt PDF files, sometimes in bulk operations, without opening any PDF tool. This feature is now available in TMS Cryptography Pack and this short post just shows how easy it is to use.


Introducing TPdfEncryptor

The new TPdfEncryptor  class is straightforward.

  TPdfEncryptor = class(TTMSCryptBase)
  private
    FCrypto: IPdfCryptoProvider;
  public
    constructor Create(AOwner: TComponent; const ACrypto: IPdfCryptoProvider);
    function Encrypt(const APdf: TBytes; const AUserPassword: string;
      const AOwnerPassword: string = '';
      APermissions: TPdfPermissions = [Low(TPdfPermission)..High(TPdfPermission)]): TBytes;
    procedure EncryptFile(const ASource, ADest, AUserPassword: string;
      const AOwnerPassword: string = '';
      APermissions: TPdfPermissions = [Low(TPdfPermission)..High(TPdfPermission)]);
    function Decrypt(const APdf: TBytes; const APassword: string): TBytes;
    procedure DecryptFile(const ASource, ADest, APassword: string);
  end;

The crypto has been completely isolated and can be accessed through a specific interface that wraps the usual primitives such as random sequence generation, SHA2 (all key sizes) and the AES (all key sizes too).

  IPdfCryptoProvider = interface
    ['{6F1C7A52-3B1E-4D0C-9A57-2E8D4C0B7A11}']
    function RandomBytes(ACount: Integer): TBytes;
    function Hash(AAlgo: TPdfHashAlgo; const AData: TBytes): TBytes;
    function AesCbcEncryptNoPad(const AKey, AIV, AData: TBytes): TBytes;
    function AesCbcDecryptNoPad(const AKey, AIV, AData: TBytes): TBytes;
  end;

Using TPdfEncryptor

Whereas encrypting and decrypting a PDF file require some amount of code, as for signing and verifying, the high-level TPdfEncryptor class makes these operations extremely simple.

Here is a PDF encryption example from the VCL demos (it also works with FMX and in console mode). This app uses a form, 2 buttons, a TMemo and a TOpenDialog.

procedure TMainForm.EncryptBtnClick(Sender: TObject);
var
  s: string;

begin
  if OpenDialog.Execute = false then
    Exit;

  // This is a demo. In a real app, choose a stronger password!
  PdfEncryptor := TPdfEncryptor.Create(nil, TTmsPdfCrypto.Create); // uses TTmsPdfCrypto for the crypto engine
  try
    s := '.\' + TPath.GetFileNameWithoutExtension(OpenDialog.FileName) + '.enc.pdf'; // or keep the initial name
    PdfEncryptor.EncryptFile(OpenDialog.FileName, s, 'AnyPassword');
    MainMemo.Lines.Add('File encrypted: ' + s);
  finally
    PdfEncryptor.Free;
  end;
end;

And decrypting isn't more complicated.

procedure TMainForm.DecryptBtnClick(Sender: TObject);
var
  s: string;

begin
  if OpenDialog.Execute = false then
    Exit;

  // This is a demo. In a real app, choose a stronger password.
  PdfEncryptor := TPdfEncryptor.Create(nil, TTmsPdfCrypto.Create);
  try
    s := '.\' + TPath.GetFileNameWithoutExtension(OpenDialog.FileName) + '.dec.pdf'; // or keep the initial name
    PdfEncryptor.DecryptFile(OpenDialog.FileName, s, 'AnyPassword');
    MainMemo.Lines.Add('File decrypted: ' + s);
  finally
    PdfEncryptor.Free;
  end;
end;


Conclusion

PDF encryption/decryption has been on the back burner for quite some time and is now in TMS Cryptography Pack with a new class: TPdfEncryptor. It can be used in any Delphi application for a single use or batch operations, for which manual encryption/decryption can be quite painful.










Bernard Roussely




This blog post has not received any comments yet.



Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post