-------------------------------------------------------------- Runtime-loadable encryptor/decryptor modules for Pegasus Mail. Pegasus Mail System, Copyright (c) 1990-95, David Harris, All Rights Reserved -------------------------------------------------------------- The hot topic on everyone's lips is "privacy". And, as usual, the computer industry is in the process of confusing and disrupting the issue beyond recognition... We have factions all over the place each arguing passionately for its own most beloved encryption scheme, and some of the rhetoric is getting pretty heated. Add to the proliferation of interests the USA's ridiculous export laws on encryptors and the sum is trouble. As far as I can tell, encryption is going through what seems to be an industry-standard cycle of chaos: everyone suddenly realises there's a lack/opportunity/need and rushes to promote the idea they like best; a small war develops during which the users and peripheral developers are left bemused and bewildered amongst the welter of extravagant claims and counter-claims, then eventually (usually after two or three years of total pandemonium) the group with the most clout (although not necessarily the best product) will win out and become "the standard". I've been through this rat race several times and have no desire whatever to go through it again; on the other hand, my USERS have very legitimate concerns about privacy. So what do I do? Easy - I pass the buck. WinPMail v2.2 and later supports third-party, runtime loadable modules to handle encryption and decryption of mail. A special mechanism has been defined that allows Pegasus Mail to detect that a third party encryptor has been used and to determine whether the matching decryptor is available on the system. The built-in encryptor will remain available for those sites who only need moderate levels of message security. WinPMail will define an open interface for third-party encryptors and it is then up to other people to write the code. What I envisage actually happening is people writing "shell interfaces" for WinPMail - i.e., modules that take the calls I make and translate them into calls to other programs, such as PGP or whatever, returning the result. I have gone to considerable lengths to find a balance between simplicity and functionality in designing this interface: an encryptor module can be implemented with as few as three exported functions, yet has support for greater functionality as required. The primary features I wanted to be able to support were encryption/decryption and both the generation and validation of digital signatures. The interface is a variant of WinPMail 2.0's Extension Manager Interface: each encryptor/decryptor is implemented as a DLL exporting the following functions by name: int FAR PASCAL encrypt_file (char *sourcefile, char *destfile, char *recipient, char *key, int textfile); // Encrypt the contents of a file: if "textfile" is non-zero, // then the file may contain 8-bit data, but will have normal // text file CR/LF line endings. If "textfile" is zero, the // encryptor routine should presume that the file has unknown // or explicitly binary contents. "recipient" contains the // address of the person to whom this message is being sent. // "key" contains whatever key the user entered, or may be // NULL if the encryptor's FFF flags indicate that it does // not require a key. // // On entry, the source file will exist, the destination file // will not: the encryptor should create the destination file // file and place the ciphertext version of the plaintext file // file in it in a format ready for transmission. The module // should NOT delete the plaintext file. // // Returns: 1 if the file was successfully encrypted. // 2 if the file was successfully encrypted but // may contain 8-bit data and should be sent // encoded using BASE64. // 0 on failure. int FAR PASCAL decrypt_file (char *sourcefile, char *destfile, char *key); // Decrypt a message into a format suitable to be displayed in // a message reader. "sourcefile" contains an image of the message // (not the actual message itself) complete with all header // information intact. The destination file will not exist and // should be created by the decryptor. // // This routine should return 2 if the message data cannot be // displayed as text (ie, is binary). // // Returns: 1 if the file was successfully decrypted // 2 if the file was decrypted but is non-textual // 0 on password or system failure // // IMPORTANT NOTE: For encrypted components of MIME multipart // messages, only the encrypted component from the message will // be passed to the encryptor, along with the headers from the // message proper. Encryptor modules may also export the following optional functions: int FAR PASCAL sign_file (char *sourcefile, char *destfile, char *recipient, char *key, int encrypt_as_well); // Compute and attach a digital signature to the message passed // in "sourcefile". The message should be rewritten with the // signature attached in the proper place in "destfile", which // will not exist on entry. "Sourcefile" will contain the body // of the message to sign, but will NOT contain the message // headers. If "encrypt_as_well" is non-zero, the file should // be both encrypted and signed, using whatever method is // appropriate. // // Returns: 1 if the message was successfully processed // 2 if the file was successfully processed but // may contain 8-bit data and should be sent // encoded using BASE64. // 0 if an error occurred during processing // -1 if the operation is not supported int FAR PASCAL verify_signature (char *sourcefile, char *text); // Attempt to verify the digital signature (if any) associated // with the message passed in "sourcefile", which contains a // complete image of the message including headers. This // routine should not assume that the message actually has // a digital signature, and should be ready to deal with the // situation where none is present. // // The "text" parameter points to a string 80 characters long // into which the verify routine can write any descriptive // text about a valid signature that should be reported to // the user. // // Returns: 1 if the digital signature was valid // 0 if the digital signature was invalid // -1 if no digital signature could be found // -2 if the operation is not supported int FAR PASCAL destroy_file (char *sourcefile); // If this function is exported, WinPMail will call it when it // has finished with a temporary files created in the process // of encryption or decryption. It is up to the module what it // does with the file, although the expectation is that it will // zero the contents and delete it. // // Note that if this function is not exported, WinPMail will // destroy the file by writing 0s into every byte then // deleting it. // // Returns: 1 if the file was destroyed // 0 if the file was not destroyed (in which // case WinPMail will delete it as described). int FAR PASCAL key_management (char *sourcefile); // This is the only function in this API which actually // specifically requires that the encryptor module provide // a user interface. The expectation is that it will open a // modal dialog offering a few simple key management choices // for the user. If "sourcefile" is non-null, it will point // to a filename which contains the image of a message selected // by the user (possibly for extraction of a public key // fingerprint, or something similar). Important considerations: * Blocking: If an encryptor module has to call another process to perform its function, then it is the encryptor's duty to ensure that control does not return to WinPMail before the process is complete - in other words, WinPMail regards encryptor actions as atomic. * Line termination: Internet mail uses CR/LF line endings, and Pegasus Mail enforces this scheme. While in transit, line endings in a message may be disturbed, and if a message originally contained a line ending scheme that is illegal in Internet terms (such as the unix LF-only termination), then the line endings may be arbitrarily altered to conform with Internet standards in transit. If the position or nature of line termination is significant to an encryption module, it should ensure that the encrypted data is "armoured" for transit as part of the encryption process; some encryptors, such as PGP, support this idea already, but if this is not the case with your encryptor, you will have to return the value 2 to WinPMail to have it armour your data using MIME BASE64 encoding. Interface: Runtime loadable encryptors are implemented as a variant of the WinPMail Extension model. They should be implemented as a standard extension that exports the extra functions described above. Encryptors have access to the full Extension Manager API set except for those functions specific to READER extensions. Just as with regular extensions, Pegasus Mail learns about encryptors via Form Fact Files (FFF files); it uses the "Form Triggers" keyword in the .FFF file as a regular expression describing some identifying characteristic of a message that the encryptor module can handle. The regular expression is applied to the headers, and to the message body for the number of lines specified in the "# of lines to probe for enclosures" setting of the Advanced Settings preferences dialog. All Pegasus Mail Extensions support a "tagname" - an identifying mark that is written into an "X-Tagname:" field in messages generated by the extension. For encryptor extensions the tagname field is particularly important, since it will usually be the basis for detecting that a particular encryptor has been used to perturb the message. Developers of encryptor extensions are urged in the strongest possible terms to register their tagnames with the author following the guidelines in WPMFORMS.TXT, the Extension Manager reference found in the FORMS\ subdirectory of a standard WinPMail 2.x installation.