GSoC 2017 - Integrating with Postorius and Hyperkitty

Since a plugin-like out-of-tree approach is required for implementing encrypted lists into Mailman, a straight forward integration into Postorius and HyperKitty (as first proposed) by making them “aware” of the encrypted lists plugin is not possible.

Thus a new approach for providing their functionality and conforming to the project requirements is necessary. I see three possible pathways forward and a middle-ground between them.

Standalone django app#

A new django app will be created, using django-mailman3 as a base, that will implement all the web based functionality for encrypted mailing lists, such as:

  • Displaying the List key for all public encrypted mailing lists.
  • List key management for list admins
  • User key management
  • Encrypted archives, that are server unencrypted (effectively replaces HyperKitty for encrypted lists)

This app will then be run besides Postorius.

A fork/patchset approach#

This approach will create a fork of Postorius and HyperKitty that will integrate changes necessary for the encrypted lists plugin seamlessly. Thus users wanting to use encrypted mailing lists will have to setup Postorius and HyperKitty from this fork.

Wrenching it in#

This approach tries to integrate all of the functionality using configurable options of Postorius and HyperKitty. For example storing messages encrypted could be done via a custom django.db.backend. Receiving messages encrypted could be done via a small custom django app that will receive them, decrypt and pass to HyperKitty decrypted.

A middle-ground#

Somewhat of a middle ground seems to be most sensible. A standalone app will be necessary to provide functionality that is simply not possible to be integrated into Postorius and HyperKitty sensibly. This app will mostly provide key management (user and list), receive the messages encrypted and so on. However Postorius and HyperKitty will work with the least amount of “wrenching it in” as possible.

GSoC 2017 - PGPMailman plugin


  • pgpmailman - A Core plugin.

    • styles - Both styles generate a list keypair based on plugin settings on list creation as well as set other attributes for an encrypted mailing list. Such as the custom encrypted chain.

      • EncryptedDefaultStyle
      • EncryptedAnnounceStyle
    • pgp

    • rules

      • EncryptionRule - Decrypts message and enforces per-list encryption requirements.
      • SignatureRule - Checks message signature and enforces per-list signature requirements. Strips signature to msgdata.
    • chains

      • EncryptedOwnerChain - Passes message through EncryptionRule before letting it continue default-owner-chain.
      • EncryptedPostingChain - Passes message through EncryptionRule and SignatureRulebefore letting it continue default-posting-chain.
    • commands

      • KeyEmailCommand - Handles user key management through the key command.
      • KeyCLICommand
    • runners

      • EncryptedOutgoingRunner - Encrypts and optionally signs for configured lists. This is a runner and not a Pipeline since we need to encrypt all outgoing messages, so digests, virgin messages, posts…
    • archivers

      • EncryptedHyperKittyArchiver - Fetches list archive public keys from pgphyperkitty, uses them to send messages to archive encrypted, for encrypted lists.
  • pgphyperkitty- Django app, receives messages encrypted with list archive keys, decrypts them and passes them to HyperKitty. Also generates, holds and provides(public part) list archive keypairs.


Rules shouldn’t change the message as they process it, since, well they are “rules” not “handlers”. However other Mailman’s rules need the message plaintext after decrypting for processing, so they cannot receive the message as it arrived encrypted. One solution would be to use a custom Incoming runner to sort-of unwrap the PGP/MIME message from encryption and signature (storing it in msgdata) and then pass it to the default Incoming runner to run chains. This would also make sense from a PGP/MIME standpoint as the “real” message is really the encrypted content so for that’s what other Mailman rules should get in the msg object.

Storing of user and list related metadata is unsolved. This means storing the user key fingerprint for each user / address, as well as storing per-list configuration. The list key fingerprint might not need to be stored as the key can be looked up by gnupg.user_id == list_fqdn. The plugin can have it’s own db although this means data duplication. A solution I see would be to allow plugins to store arbitrary metadata in the core db attached to certain models. So that the mailinglist model would have another attribute plugin_data of PickleType which would really be a dict with the plugin name as keys, with additional api allowing a plugin to access it’s metadata stored in this object.

Extending the Postorious and Hyperkitty interface is unsolved. Since plugins cannot add routes to the REST api. A solution I see that would be general and also require little changes to core would be to let plugins add custom routes to /plugins/<plugin_name>/... which could be then accessed either from a Postorious plugin or a custom app. Maybe with falcon.API.add_sink()?

Even when extending the REST api at core side is possible as just described, that still leaves integrating into HyperKitty and Postorius somehow, out-of-tree, as a django app. Looking at how HyperKitty and Postorius plug into each other currently, we see direct references at each other in the templates:

    {% if 'hyperkitty' in INSTALLED_APPS %}
    {# insert hyperkitty link #}
    {% endif %}

While that might be okay for integrating HyperKitty and Postorius together, and it’s even used at very few places and seems to not be the best solution, it’s not practically usable for integrating this plugin. Ideal integration will encrypt messages when sending them to HyperKitty while showing them decrypted to users. I am thinking of having a custom encrypted HyperKitty archiver that will handle encrypting with proper archive key at the core side and a custom django app at the HyperKitty side that will receive the message, decrypt it and pass it to HyperKitty decrypted. That however leaves the messages decrypted in HyperKitty’s DB so doesn’t really fulfill project requirements. In addition a custom DB engine can be used in HyperKitty’s settings that wraps whatever DB engine and encrypts/decrypts objects on the fly, although I am not sure of the doability of this.


Just installing the plugin into the same virtualenv as the Mailman instance, and setting up the proper options in mailman.cfg should work.

GSoC 2017 - Mailman encrypted lists update

Plugin API enhancements in Core#

To cleanly implement encrypted mailing lists as a plugin to Mailman Core I propose several general changes to the plugin api, to allow for cleaner integration of plugins, more flexibility and easier plugin deployment. First I present the current state of pluggability in Mailman core and then the proposed changes.

Current state#

Relevant mailman-developers thread from GSoC 2015

Example plugin

  • A plugin creator has many ways of “injecting” his code to run at certain phases of Mailman’s operation, since Mailman looks for its classes and components dynamically, it doesn’t care whether they are from a plugin or originally from core.
    • Implementing IHandler, IChain, IRule, IEmailCommand, ICLISubCommand or IStyle and placing modules containing the classes in the appropriate directories where Mailman finds them and instantiates them.
    • Implementing IRunner and adding the custom runner to mailman.cfg.
    • Implementing IArchiver and adding the custom archiver to mailman.cfg.
    • Implementing IMailTransportAgentLifecycle and setting the custom MTA in mailman.cfg.
    • Setting a custom callable in pre_hook or post_hook (only one callable per hook).
  • Core config variable ext_dir is unused.
  • There is not much documentation / examples of plugin creation, however core is very well documented so it’s just a matter of figuring out what’s pluggable or not.

Proposed changes#

  • Add configuration option similar to config.styles.paths to Handlers, Rules, Chains etc.. Which Mailman will use to look for components, so that plugins can just be accessible on the python path and not necessarily inside the Mailman package. Or use just one path per plugin and a standardized plugin structure:
    • plugin package
      • handlers
      • rules
      • chains
      • commands
      • pipelines
      • styles
  • Let plugins add Pipelines the same way they can add Handlers, Rules etc…
    • This means refactoring BasePipeline, OwnerPipeline, PostingPipeline, VirginPipeline from into a package mailman.pipelines
    • Use find_components
  • Let plugins subscribe to receive events.
  • Let List creator specify List Style when creating it through Postorius.
  • Allow multiple callables in pre_hook and post_hook run in order specified.
  • Drop ext_dir.

Generating EC domain parameters - ecgen

Build Status GitHub release

ecgen is a tool for generating Elliptic curve domain parameters. While working on generating some interesting EC domain parameters for ECTester I found out there aren’t really any good tools for doing so. Cryptographic libraries don’t offer generating custom curves, they just offer preset ones or let you set custom ones. The only tools I found were ECB, LiDIA/GEC, MIRACL and cm. They all have their drawbacks however, ECB is limited in what parameters are modifiable and is closed source, LiDIA is unmaintained, and cm also doesn’t support the flexibility in parameters I needed. To add to that I lost the link to MIRACL and could not remember it’s name. So ecgen is what I started working on.

Since Elliptic Curve domain parameters are a rather complex object, generating them with various constraints and parameters is also complex and there are various algorithms for doing so. Generally two methods are used in practice. One is randomized and works as you might imagine from the name, by generating random domain parameters within some constraints, computing the rest of the parameters and hoping they satisfy the rest of the constraints. A variation of this is the ANSI X9.62 verifiably random algorithm. The other method is based on the theory of Complex Multiplication and is able to directly generate Elliptic Curve domain parameters with required constraints.

Generally the biggest problem when generating Elliptic Curve domain parameters is calculating the order of the curve specified by the curve equation. Since when this order is known the rest of the parameters (generators, group structure…) are found rather easily.

Computing this order given the equation is hard, there are several rather complex algorithms, some of which are fast for curves over (AGM), some for curves over (Schoof’s, SEA).


ecgen --fp/--f2m BITS

Field specification#

  • --f2mBinary field.
  • --fpPrime field.

Generation options#

  • -c / --count=COUNTGenerate multiple curves.
  • -i / --invalidGenerate a set of invalid curves, for a given curve (using Invalid curve algorithm).
  • -k / --cofactor=BOUNDGenerate a curve with cofactor up to BOUND TODO - NOT FINISHED
  • --anomalous Generate an anomalous curve (of trace one, with field order equal to curve order).
  • -K / --koblitzGenerate a Koblitz curve (a = 0).
  • -n / --order=ORDERGenerate a curve with given ORDER (using Complex Multiplication). TODO - NOT IMPLEMENTED
  • -p / --primeGenerate a curve with prime order.
  • --points=TYPEGenerate points of given TYPE (random/prime/none).
  • -r / --randomGenerate a random curve (using Random approach).
  • -s / --seed[=SEED]Generate a curve from SEED (ANSI X9.62 verifiable procedure). TODO - NOT IMPLEMENTED
  • -u / --uniqueGenerate a curve with only one generator.

IO options#

  • -t / --format=FORMATFormat to output in. One of [csv,json], default is json.
  • -f / --input=FILEInput from FILE.
  • -o / --output=FILEOutput into FILE. Overwrites any existing file!
  • -a / --appendAppend to output file (don’t overwrite).
  • -v / --verbose[=FILE]Verbose logging (to stdout or FILE).


  • -d / --data-dir=DIRSet PARI/GP data directory (containing seadata package).
  • -m / --memory=SIZEUse PARI stack of SIZE (can have suffix k/m/g).
  • --threads=NUMUse NUM threads.
  • --thread-stack=SIZEUse PARI stack of SIZE (per thread, can have suffix k/m/g).


Generate a prime field, prime order, uniquely generated 192-bit curve, don’t ask for input try random values:

> ecgen --fp -r -p -u 192

Generate 5 random, binary field, 163-bit koblitz curves:

> ecgen --f2m -r -k -c5 163

Generate invalid curves to a file, for a given prime field 192-bit curve:

> ecgen --fp -i --output=invalid.json 192
p: <input prime>
a: <input a param>
b: <input b param>

Generation methods#

Three different EC curve parameters generation methods are implemented.

Efficient Algorithms for Generating Elliptic Curves over Finite Fields Suitable for Use in Cryptography - [Baier]

Generation Methods of Elliptic Curves - [Baier, Buchmann]

Random approach#

  • Generates field and equation parameters:
    • randomly
    • using ANSI X9.62 verifiably random method(from seed), until a curve with requested properties appears.
    • given input
  • Can generate curves repeatedly until one satisfies requested properties:
    • -p / --prime generates curves until a prime order curve is found.
    • -K / --koblitz generates a curve with fixed A = 0 parameter.
    • -u / --unique generates a uniquely generated curve (with one generator/cyclic group).
    • etc..

Invalid curve generation#

Complex multiplication#


git clone
cd ecgen
git submodule update --init



ecgen uses the PARI/GP library for elliptic curve arithmetic and it’s SEA point counting algorithm implementation. It also requires the additional seadata package (seadata and seadata-big recommended for large curves).


  • lib/parson ©MIT
  • lib/sha1 ©MPL / GPLv2 or later

parson is used to input and output JSON and is included in the lib/ directory.

A SHA-1 implementation by Paul Kocher, based on the SHA 180-1 Reference Implementation (for ANSI X9.62 algorithm) is used and also included in the lib/ directory.


This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see

© Eastern Seaboard Phishing Authority

1   2   3