This document represents Protocol Version 0xFA.
Previous versions can be found here.
Pest is a peer-to-peer network protocol intended for IRC-style chat. It is designed for decentralization of control, resistance to natural and artificial interference, and fits-in-head mechanical simplicity -- in that order.
Pest explicitly rejects the inherently-centralizing concepts of IRC (not even speaking of the even more noxious "walled-garden" atrocities perpetrated in recent years.) In place of IRC's collectivist concept of the server, every Pest user is instead the sole operator of a stand-alone station. A Pest station exchanges authenticably-encrypted Message
s exclusively with an operator-selected set of peers known as a WOT
(web of trust.)
An IRC server is typically inhabited by a multitude of casual users and policed by a small group of privileged curators. A Pest station, on the other hand, is under the exclusive control of one person: its operator.
Pest stations organize into nets. A net is formed by a group of station operators with a common interest. An operator who wishes to join a net must peer with at least one existing station in that net.
A broadcast Pest Message
will reach every reachable member of its sender's net. Nets may easily and organically undergo schismatic splits, or, on the contrary, combine into larger nets, whenever the individual station operators so desire.
A prospective Pest station operator does not need to ask permission from anyone; and the only other people who will need to know about the mere existence of the station will be its peers.
To join a Pest net, an operator must simply find one or more current members of that net who would peer with his station, and securely exchange a small amount of information. An active Pest station may have as few as one peer, or as many as its hardware is able to service at the desired bandwidth capacity.
A Pest station operator may choose any handle he likes, so long as it does not collide with that of a peer. Importantly, one person may easily operate multiple Pest stations, and inhabit multiple disjoint nets; and may use, if he wishes, a different handle on each net.
All Pest Message
s are authenticable -- a station will only process an incoming Message
if it carries a valid Seal
(i.e. signature) from a peer (though in some cases, it may not have been authored by that peer.)
However, they are also repudiatable (i.e. non-opposable) -- since all packet Seal
s are produced with symmetric keys, the recipient of a Message
cannot, at any point in time, prove to a third party1 that he was not in fact the author of that message.2
Because Pest does not impose -- unlike IRC -- a hierarchical structure of control, it offers no direct equivalents to IRC's "kick" and "ban". Instead, an annoying, tedious, or habitually-spamming station operator may be rebuked by his peers; if he persists in his misbehaviour -- ignored via Usenet-style killfiles; and, if he proves incorrigible -- unpeered. Sooner or later, the malefactor will find himself where he belongs: either alone or in the company of his own kind.
Pest broadcast messages are flood-routed -- i.e. they traverse all available propagation paths. Unlike IRC relays, Pest stations may be connected in any topology their operators prefer; concretely, loops are permitted, in the interest of decentralization.
Infinite packet storms are prevented via deduplication at the station level -- rather than by prohibiting loops, or via a spanning tree protocol, or any other traditional routing schemes which enforce acyclic connection graphs by demanding the existence of "root nodes", "supernodes", centrally agreed-upon tables, etc.
Pest station operators are not merely permitted, but in fact encouraged to form richly cyclic connection graphs for the highest attainable resiliency.
Pest Message
s travel as individual authenticably-encrypted datagram packets; and the identity of such a packet's sender is determined strictly by attempting its verification against all keys known to the receiver.
A Pest station is able to quickly reject malformed, spurious, corrupted, or duplicate incoming Message
s. At the same time, the address fields provided by the IP protocol play no role in the validation of a Pest packet. Consequently, Pest traffic may be easily and safely carried over an otherwise-unsecured "shared-everything" medium, such as radio, or via several conventional Internet connections operated in tandem.
Pest Message
s include hashes of earlier Message
s to enable detection of loss in transit and allow for retransmission upon request. As a result, Pest is insensitive to connectivity disruptions (whether accidental or malicious), and Pest traffic may be carried reliably over lossy channels (radio, poor-quality Internet connections, etc.)
From a Pest station's point of view, a stranger is any Internet-connected machine other than a peer.
Unlike virtually all traditional Internet protocols, Pest does not talk to strangers. At all.
Strangers may, of course, send arbitrary packets to anywhere at all -- including a Pest station. However, because a stranger (by definition) does not know any of the keys in that station's WOT
, all such packets will simply get thrown away3 as invalid.
An invalid packet is one which is determined to be martian, duplicate, or stale. Conversely, a packet which is neither martian, duplicate, nor stale is considered valid.
Invalid packets do not necessarily come from strangers -- they may be sent by peers; at times -- deliberately.
It is recommended that a Pest station be provisioned with sufficient hardware resources to process incoming packets at line rate (i.e. at the maximum rate at which they may arrive via the station's physical network interfaces.)
An incorrectly-sized packet received by a Pest station -- or a correctly-sized one which does not bear a valid Seal
from one of its peers4 is referred to as a martian. All such packets are silently discarded.
An incoming packet which is correctly-sized and bears a valid Seal
is thereby not a martian. However, it may still turn out to be a duplicate. A packet is considered a duplicate if the Message
it bears is identical to one encountered in any previously-accepted packet. Duplicates are silently discarded.5
Any packet bearing a Message
which has expired, or appears to come "from the future" is considered stale and -- even though it may be valid in every other respect -- silently discarded.6
A stranger who is able to capture some or all of the traffic emitted by a Pest station is referred to as a snoop.
Pest packets carry no unencrypted information whatsoever -- and in particular, contain no "magic numbers" or other fields with predictable values of any kind which could identify them to a third party as Pest packets or reveal any information at all concerning their payloads.
Consequently, a Pest packet intercepted en route conveys no useful information to a snoop, apart from the mere fact that a particular machine had sent a string of 496 apparently-random bytes to a certain other.
A network of Pest peers may, by mutual agreement, pad their packets beyond the default 496 byte length, to circumvent a (hypothethetical) ISP ban against 496-byte packets. However, steganographic techniques, necessary as they may one day become, are beyond the scope of this document.
In the interest of thwarting traffic analysis, a Pest station may occasionally transmit rubbish packets to peers, or even to randomly-generated IP addresses.
Additionally, a station may occasionally transmit copies of a packet keyed for a given addressee to one or more randomly-selected other peers, in random order. All recipients other than the intended addressee will harmlessly reject the martian; while the task of a snoop charged with determining "who is talking to whom" becomes rather unenviable.
The operator of a Pest station -- who may be a human or a bot -- has absolute control of the station and its configuration.
A station communicates exclusively with:
The operator -- via the operator console, an IRC-compatible interface.
An operator-selected set of remote peer stations -- via datagrams.
In order for a pair of Pest stations to communicate, their operators must decide to peer them by agreeing7 on a shared secret key K. Every packet sent by one peer to the other is signed/enciphered by the sender and verified/deciphered by the receiver using this K
.
Additionally, the peers must establish one another's reachable Address
es. If one or both of them has a routable, static public IP, this may be accomplished via the AT Command
; otherwise it will take place automatically, supposing the peers are able to reach a given Pest Net.
If, at some future time, the operator of either station no longer wishes to continue in this relationship, he may terminate the peering unilaterally, and the two stations will then be said to have unpeered. A former peer is treated exactly the same as any other stranger.
A Pest station may have any number of peers. One or more8 key K
for each peer is kept in a data structure referred to as the station's WOT
. The operator may alter this structure at any time, and changes take effect immediately. The WOT
is never altered by the station except by direct command of the operator.
Each peer entry in the WOT also contains one or more handles known to be in use by the peer, as well as certain other information pertaining to that peer.
A Pest station has another data structure, the AT
(Address Table), which holds the last known Address
9 of each WOT peer. The AT
is used exclusively for determining where to send outgoing packets.
Like the WOT
, the AT
may also be altered by the operator at any time. Unlike the WOT
, the AT
is automatically updated by the station when any cryptographically-valid packet is received from a new (i.e. not currently in the AT
) Address
. The AT
retains one entry per WOT
peer.
A Pest station is controlled by its operator through the operator console -- an interface implementing a minimal subset of the classical IRC protocol, permitting the use of traditional IRC clients (including bots) as Pest "front-ends."
Traditional IRC offers no provisions for secure authentication or encryption; hence, it is recommended that a Pest station and its IRC client reside in one physical machine. Alternatively, they may run on separate machines and connect via an SSH tunnel or similar mechanism.
Per RFC-1459, an IRC message shall not exceed 512 bytes in length, including the mandatory CR-LF terminator. Thus, there are 510 bytes available for a command entered into the console (including its prefix and parameters); and similarly for any message emitted via the console.
The console will accept, at minimum, the following IRC-compatible commands:
Command | Arguments | Description |
---|---|---|
USER |
username hostname servername realname | The string username must equal a preconfigured value stored on disk, or the console connection will be terminated immediately. It is not used for any other purpose. None of the other parameters are used for any purpose, but may be present. |
PASS |
password | This is a password, or a derivative thereof; the exact authentication mechanism is unspecified. If the password is found to be invalid, the console connection will be terminated immediately. Pest station operators should not rely solely on this mechanism for access control! |
NICK |
HANDLE |
Every Message originating at this station will have a Speaker equal to HANDLE . Importantly, HANDLE may not collide with any peer handle found in the station's WOT ; nor may PEER or AKA later be invoked with an argument equal to this HANDLE . |
JOIN |
#pest |
Valid USER , PASS , and NICK commands must be received prior to accepting this command. The argument must start with # . This is a pseudochannel which must be used in all subsequent IRC commands which require a channel (e.g. PRIVMSG , PART .) In all examples henceforth -- will be illustratively #pest , but in fact it may be any string of up to 128 bytes in length. |
PART |
#pest |
Has no effect. |
VERSION |
Display a description of the implementation and version of the protocol currently in use. | |
PRIVMSG |
(#pest or HANDLE ) MESSAGE |
Transmit MESSAGE as a Broadcast Text Message to the Pest Net (if first argument starts with # ) or alternatively as a Direct Text Message to HANDLE . In the latter case, HANDLE must refer to a peer for whom at least one key is known and an AT entry exists. If these conditions are not satisfied, or if JOIN and its pre-requisite commands have not been received, a warning is displayed and the command has no effect. The MESSAGE is not to be altered in any way (including manipulation of leading or trailing white space) by the Pest station prior to encoding; with the exception of chunking into Pest Message -sized slices, when required; and the interception of % -prefixed Control Commands (see below). |
Control commands allow a Pest station's operator to view or update the station's configuration.
All control commands must be found at the beginning of a string entered into the operator console, and are prefixed with %
(e.g. %WOT
). Any line entered into the operator console which begins with %
(i.e. appearing as an IRC message originating from the operator of the form PRIVMSG foo %bar
, regardless of foo
) must be treated as a control command, and a correct Pest implementation must take care to filter these lines to prevent emission of the command or its arguments as a text Message. Whitespace may precede the %
command prefix and is to be disregarded. If a station operator finds it necessary to transmit a text Message starting with %
, he may prefix it with a second %
, i.e.: %%
.
A control command may be issued at any time, and must take effect (including preserving any state change to persistent storage) immediately. Responses to control commands will be emitted through the console in the form of IRC NOTICE messages.
The following basic set of control commands must be supported:
Command | Arguments | Description |
---|---|---|
WOT |
Display the current WOT , with complete (apart from keys) data concerning each peer. This includes the peer's handles; whether the peer is paused; the timestamp of the most recent packet received from the peer; and the current address stored in the AT for the peer. |
|
WOT |
HANDLE |
Display all WOT data concerning the peer identified by HANDLE , including all known keys, starting with the most recently used, for that peer. |
PEER |
HANDLE |
Declare a new peer, identified by HANDLE . This command is required but not sufficient to establish communication with the peer (see also KEY and AT .) |
UNPEER |
HANDLE |
Permanently discard all data concerning the peer identified by HANDLE , including keys and AT entries. |
AKA |
HANDLE ALIAS |
Permit the use of the string ALIAS synonymously with the previously-known HANDLE (which may in turn be the peer's original handle, or an alias added via this command.) |
UNAKA |
HANDLE |
Remove HANDLE from the WOT . However if it is any peer's only known handle, the command has no effect and a warning is displayed. |
PAUSE |
HANDLE |
Temporarily disable all communication with the peer identified by HANDLE , without discarding any data. |
UNPAUSE |
HANDLE |
Re-enable communication with the peer identified by HANDLE . |
KEY |
HANDLE KEY |
Add a KEY for the peer identified by HANDLE . KEY is in all cases a base64-encoded 512-bit value, and may not previously exist anywhere in the WOT . (If it was found to exist, an error message is displayed and nothing further happens.) If HANDLE is unknown, a warning is displayed. If KEY does not base64-decode to precisely 512 bits, an error message is displayed to this effect, and nothing further happens. |
UNKEY |
KEY |
Remove the given KEY from the WOT . However if KEY is any peer's only known key, the command has no effect and a warning is printed. |
GENKEY |
Use the system TRNG to generate and display a new KEY suitable for use with KEY . No change is made to the WOT . |
|
REKEY |
HANDLE |
Attempt a Rekeying with the peer specified by HANDLE . If no handle is specified, attempt rekeying with each peer in the WOT , in random order. All successful rekeyings are reported to the operator console (without displaying keys.) |
RKTOG |
ENABLE or DISABLE |
Toggle processing of Rekeying requests. Defaults to disabled. |
GAG |
HANDLE |
Add HANDLE (which may not correspond to a WOT peer!) to the killfile. Any incoming Message where Speaker matches a killfile entry will not be processed. |
UNGAG |
HANDLE |
Undo the effect of a previously-issued GAG command. |
AT |
Display the current AT. | |
AT |
HANDLE |
Display the current AT entry for the peer identified by HANDLE . |
AT |
HANDLE ADDRESS |
Set the current ADDRESS in the AT for the WOT peer identified by HANDLE . In order for two peers to communicate, at least one of them must issue this command to add the other's address to his AT. Subsequently, this value will be updated as required as packets are received. |
KNOB |
Displays a list of all implemented knobs (operator-configured constants.) | |
KNOB |
KNOB |
Displays the current value of KNOB . |
KNOB |
KNOB VALUE |
Sets the knob identified by KNOB to VALUE . |
CUT |
INTEGER |
Sets the station's bounce cutoff to the given INTEGER between 0 and 255. If equal to 0, the station will process only direct messages. |
CUT |
Displays the currently-set bounce cutoff value. | |
RESOLVE |
HANDLE |
Resolve a fork afflicting the peer identified by HANDLE . |
BANNER |
TEXT |
Sets the banner string to be relayed to peers in Prod Message s. By default, this string corresponds to a brief description of the Pest implementation in use at the station. |
The console may support certain other commands. These use the same prefix as control commands, and include:
Command | Arguments | Description |
---|---|---|
PCUT |
HANDLE INTEGER |
Similar to CUT , but sets a bounce cutoff which applies to the individual peer identified by HANDLE . If set to equal the global cutoff previously specified via CUT , the entry is cleared. |
PCUT |
HANDLE |
Displays the value previously set via PCUT for the peer identified by HANDLE , or an error message if no such value is currently set. |
SLAVE |
HANDLE |
Intended strictly for use with bots. Set the station into slave mode with respect to the peer identified by HANDLE . The latter is referred to as a master. A broadcast message received solely via one or more peers identified as a master is treated as an immediate message; when rebroadcast, its bounce count will consequently be equal to one. More than one master may be set. |
SLAVE |
Display a list of masters that have been set via the SLAVE command. If this list is currently empty, the message "station is not in slave mode." is displayed. |
|
UNSLAVE |
HANDLE |
Removes the peer identified by HANDLE from the masters list. If the peer was not in the masters list, an error message is displayed and there is no other effect. |
UNSLAVE |
Removes all entries from the masters list. | |
ACHTUNG |
MESSAGE |
MESSAGE will be transmitted as a WOT circular, i.e. via a Direct Text addressed to each peer of the station, exactly as if it had been issued via /PRIVMSG peername MESSAGE for each peer separately. |
SCRAM |
SCRAMPASS |
If sha512(SCRAMPASS) matches a preconfigured value stored on disk, the station will overwrite all in-memory and on-disk state with random bytes and shut down. This command may trigger other programmatic actions configured in advance by the operator, either before or after zapping all station state (e.g. in a before action -- emit a pre-defined /ACHTUNG deathsquad is here! goodbye friends! ). |
The following data types are used in Pest, and must be encoded as described here:
A Integer[N]
is an integer, occupying precisely N
bytes, mandatorily in little-endian order when applicable.
A Zero[N]
is required to consist of precisely N
bytes, each equal to zero.
A AString[N]
is a seven-bit-clean (i.e. pure ASCII) string, at most N
characters in length.
The field containing the string at all times occupies precisely N
bytes, with all unused trailing bytes set to Zero
.
A UString[N]
is a validly UTF8
-encoded string, at most N
characters in length. The field containing the string at all times occupies precisely N
bytes, with all unused trailing bytes set to Zero
.
A Time
is always an exactly 64-bit value, obtained from a Pest station's 64-bit monotonic epoch clock, traditionally defined as "a 64-bit unsigned fixed-point number, in seconds relative to 00:00:00 January 1, 1970, UTC".
A Hash256
is an output of the traditional SHA-256
function, and occupies precisely 32
bytes.
A Hash512
is an output of the traditional SHA-512
function, and occupies precisely 64
bytes.
A Seal
(i.e. signature) is an output of the traditional HMAC-384
function, and occupies precisely 48
bytes. Seal
s in Pest are computed exclusively over a Ciphertext
and a PestKey's Signing Key.
A Ciphertext[N]
is a ciphertext produced with the Serpent
symmetric cipher, operated in Cipher Block Chaining (CBC) mode. N
must be a multiple of 16
(Serpent
's block size) and refers to the bytewise length of the ciphertext as well as that of the plaintext it had been produced from.
A PestKey
is a secret key shared by a given pair of Pest peers, and under no circumstances revealed -- in whole or in part -- to any third party (including other peers.)
The key identifies the peer relationship from both directions: the identity of the peer who sent a particular packet is determined strictly by attempting Seal
verification and ciphertext decryption with every PestKey
known to the recipient.
A PestKey
occupies precisely 512
bits (i.e. 64
bytes), which represent the following:
Bytes | Description | Type |
---|---|---|
32 |
K(S) (Signing Key) |
Noise[32] |
32 |
K(C) (Cipher Key) |
Noise[32] |
At all occasions where a PestKey
must be handled by a human, it is represented in Base-64 format.
Generated independently of the Cipher Key, this value is used by a pair of peers strictly to produce or verify a Seal
.
Generated independently of the Signing Key, this value is used by a pair of peers strictly to produce or decrypt a Ciphertext
.
A Noise[N]
consists of precisely N
bytes of uniformly-distributed entropic noise, obtained from a hardware TRNG where feasible.
A PestAddress
represents a two-byte port and a four-byte publicly-routable IPv4
address; it occupies precisely 6
bytes.
The first byte of this field will represent the least-significant byte of the port number; the second byte will represent its most-significant byte. (E.g. if the port number is equal to 1337
, the first byte will equal 0x39
, and the second byte will equal 0x05
.)
The IP
field is laid out in order of descending significance. (E.g. if the IP
to be encoded is 1.2.3.4
, the third byte of the PestAddress
will be equal to 0x01
; the fourth: 0x02
, the fifth: 0x03
, the sixth: 0x04
.)
A Payload
consists of precisely 324
bytes, and represents the useful cargo of a Pest Message
. The meaning of a Payload
is determined by the Command
found in the Red Packet
bearing the Message
.
A Pest Message
consists of 428 bytes, representing the following:
Bytes | Description | Type |
---|---|---|
8 |
Timestamp |
Time |
32 |
SelfChain |
Hash256 |
32 |
NetChain |
Hash256 |
32 |
Speaker |
AString[32] |
324 |
Payload |
Payload |
The station where a Pest Message
came into being is referred to as its originator.
Upon origination, a Message
is encoded into a Red Packet
; this, in turn, is encoded into one or more Black Packet
s -- one for each intended addressee (a peer to whom a copy of the given Message
is to be sent.)
A line of text entered into a station's operator console will result in the origination of one or more Direct Text
or Broadcast Text
Message
s. The addressee stations which succeed in authenticating and decoding these Message
s will emit their text Payload
s into their operator's consoles.
Given that a Pest Message
is able to carry no more than 324 bytes of Payload
, a single IRC command received from the console may require a station to originate two text Messages
. These must be appropriately chained, and their Timestamp
s must be equal. Receivers will place these Messages
into the correct order using their SelfChain
and NetChain
values.
Certain Pest Messages
bear payloads other than human-readable text and are generated in response to events other than IRC activity in the console.
A 64-bit timestamp10 from the Message
's originator, representing the time of its origination. Stations may not alter timestamps (or any other Message
fields) when relaying Broadcast Message
s.
An incoming Message
(other than a currently-expected response to a GetData
) which carries a timestamp more than 15 minutes in either direction (i.e. into the past or the future) from the moment (per the receiver's clock) it was received, is referred to as stale. Such a message is silently discarded by the receiver.
SelfChain
hashes are computed strictly for Broadcast Text
and Direct Text
Message
s. For all other Message
types, the values of these fields are undefined.
A hash11 of the most recent Broadcast Text
Message
previously sent by the originator.
A station broadcasting for the first time must set its first message's SelfChain
to zero.
If a station receives a Broadcast Text Message
where SelfChain
is equal to zero, and its Speaker
is e.g. nebuchadnezzar
, and this Speaker had never been seen previously, it will emit -- prior to the message's text -- a warning of the following form to the operator console:
Met nebuchadnezzar !
If the receiving station finds that it has no record of a previous Broadcast Text
message which hashes to the given message's SelfChain
, it will attempt to obtain a copy of such a message from its peers via GetData
. The "offending" message will be interned in the Order Buffer, giving the peers a chance to respond.
If no such response is received within the allotted interval, the Speaker
's chain is considered to be broken.
If, on the other hand, a message's SelfChain
skips over a chronologically-preceding message bearing its Speaker
, the Speaker
's chain is considered to be forked.
What happens in the event of a broken or forked chain depends on whether the "offending" Broadcast Text Message
was immediate (i.e. prima facie authentic, having been received directly from the peer corresponding to Speaker
) or hearsay.
An immediate Broadcast Text Message
is authentic by definition. Any chain defects are assumed to have been caused by in-transit packet loss or reordering.
Hence, a break may result in some number of additional attempts at GetData
, while an apparent fork will be considered resolved immediately in favour of the most recent apparent chain.
A hearsay Broadcast Text Message
with a broken chain will result in the display of the following warning:
nebuchadnezzar is broken! last.: "blah..."
... where "blah..."
is the text of the most recent preceding message from that Speaker
.
A hearsay Broadcast Text Message
with a forked chain will trigger the following warning:
nebuchadnezzar is forked! prev.: "blah..."
... where "blah..."
is the text of the previously-seen message pointed to by the SelfChain
(if available in the buffer; if not, a base-16 representation of SelfChain
is displayed instead.)
The Speaker
nebuchadnezzar
is henceforth considered forked. While he remains forked, the warning, in the above form, shall be emitted in the console (via NOTICE
) every time a message is received where Speaker
is nebuchadnezzar
.
Until the fork is resolved at the station, all messages having a Speaker
nebuchadnezzar
are displayed with e.g. nebuchadnezzar-1
, nebuchadnezzar-2
, etc. in place of nebuchadnezzar
, with the number following the dash corresponding to the identifiable fork the message is part of.
A station will consider a fork to be resolved at the station only after the station operator executes the command /RESOLVE nebuchadnezzar
(after having a stern talk with the peer(s) who had been relaying messages from the phony nebuchadnezzar
s!) Note that RESOLVE
marks the last seen SelfChain
as valid; hence, the command should be used only after the operator is reasonably certain that only the genuine nebuchadnezzar
remains on the Pest Net.
A station must not reject a broadcast message simply because its Speaker
and SelfChain
indicate a state of forkage. Doing so would make recovery from certain failures (lost packets; data corruption) impossible, and constitutes a denial-of-service vector. However, station operators are encouraged to make use of out-of-band (e.g. GPG) methods to resolve a fork, should one happen to arise; and to mercilessly unpeer anyone found to be deliberately causing a fork under whatever pretext.
A hash of the most recent Direct Text
Message
previously sent by the originator to this particular addressee.
If the receiving station finds that it has no record of a previous Direct Text
message which hashes to the given SelfChain
, it will attempt to obtain a copy from the originator via GetData
.
NetChain
hashes are computed strictly for Broadcast Text
Message
s. For all other Message
types, the values of these fields are undefined.
A hash of the most recent Broadcast Text
Message
previously seen (i.e. received or originated) by the originator.
If the receiving station finds that it has no record of a previous Broadcast Text
message which hashes to the given NetChain
, it will attempt to obtain a copy from its peers via GetData
.
In the future, NetChain
may also be used for Usenet-style threading.
Must be set to zero.
An AString[32]
representing the Handle in use by the originator. Pest Handles are mandatorily pure ASCII to abolish the homoglyph impersonation which plagued traditional chat protocols (e.g. IRC) which permitted UTF in handles.
Speaker
may not be less than 3 characters in length. It must consist strictly of alphanumeric ASCII characters, additionally including underscore (a-zA-Z0-9_
). Messages bearing a value of Speaker
which does not conform to this pattern are rejected.
The Payload
, i.e. useful cargo, of a Pest Message
.
In a Broadcast Text
or Direct Text
Message, the Payload
is a UString[324]
, i.e. a human-readable text. In other Message
types, the Payload
is typically a machine-readable data structure.
A Message
, together with certain information which helps its recipient decide what to do with it, is termed a packet. Every packet starts life as red12 (i.e. plaintext).
A Red Packet consists of 448 bytes, representing the following fields:
Bytes | Description | Type |
---|---|---|
16 |
Nonce |
Noise[16] |
1 |
Bounces |
Integer[1] |
1 |
Version |
Integer[1] |
1 |
Reserved |
Zero[1] |
1 |
Command |
Integer[1] |
428 |
Message |
Message |
16 bytes of garbage, exclusively for use as cipher nonce; obtained from a hardware TRNG where possible. This value is not used for any purpose following decryption.
Cipher nonces are used to prevent the emission of identical ciphertexts even in a situation where a given plaintext is encrypted with a particular key more than once (and similarly for Seal
s). They also increase resistance to "known-plaintext attack" of symmetric cipher and signature schemes.
A single-byte Integer which represents the number of times the Message
in this packet had been relayed between stations. A station must reject messages which have experienced more than a preconfigured number of bounces. The recommended cutoff value is 5.
A single-byte Integer representing a "degrees Kelvin" (i.e. decrementing) version.
Zero[1]
, i.e. a single byte which must equal 0.
A single-byte Integer which represents the intended purpose of the Message
carried by the packet:
Value | Command | Text? | Broadcast to Net? | |
---|---|---|---|---|
0x00 |
Broadcast Text | Yes | Yes | |
0x01 |
Direct Text | Yes | No | |
0x02 |
Prod | No | No | |
0x03 |
GetData | No | No | |
0x04 |
Key Offer | No | No | |
0x05 |
Key Slice | No | No | |
... | Undefined (Packet is rejected) | ... | ... | |
0xFE |
Address Cast | No | Yes | |
0xFF |
Ignore | No | Maybe |
This 428-byte field contains the Message
carried by the packet.
The intended purpose of the Message
is determined by the value of the command field of the packet which carried the Message
.
SelfChain
and NetChain
are valid strictly for Broadcast Text and Direct Text Message
s; in all others, these fields may contain arbitrary bytes.
A human-readable text message, intended for the broadest possible dissemination. A broadcast message is sent to every peer in the originator station's WOT
, and will be propagated to their peers, and so on.
A broadcast message will often reach stations which are not peers of the originator. From the point of view of these stations, such a message is termed hearsay; and, when displayed, it is specially marked so as to distinguish it from an immediate message.
The Payload
of a Broadcast Text
is a UString[324]
.
A human-readable text message, intended strictly for the addressee.
The Payload
of a Direct Text
is a UString[324]
.
Prod
Messages aid Pest stations in NAT penetration (via the Address Cast
mechanism) and chain synchronization (via the GetData
mechanism.)
They also allow a station operator to share an arbitrary string with his peers (e.g. advertising his particular Pest implementation, a WWW URL, etc.)
The Payload
of a Prod
consists of the following:
Bytes | Description | Type |
---|---|---|
2 | Flag |
Integer[2] |
6 | Address |
PestAddress |
32 | BroadcastSelfChain |
Hash256 |
32 | BroadcastNetChain |
Hash256 |
32 | DirectSelfChain |
Hash256 |
220 | Banner |
UString[220] |
If the supplied value of BroadcastSelfChain
, BroadcastNetChain
, or DirectSelfChain
disagrees with the addressee's, the latter may issue one or more GetData
Messages to the sender of the Prod
.
A two-byte Integer
, with permitted values of 0
(indicating that an answer to this Prod
, consisting of a Prod
from the addressee) is requested, or 1
(indicating that this Prod
is an answer to one previously received from the addressee.)
The Address
currently found in the sender's AT
entry for the addressee. It is identical to the one to which the sender intends to transmit the packet bearing this message.
The sender's current Broadcast SelfChain
.
The sender's current Broadcast NetChain
.
The sender's current Direct SelfChain
with the addressee.
An arbitrary human-readable description of the sender's Pest station. This string may be set by an operator via the BANNER
command.
The Payload
of a GetData
Message consists of a hash identifying a previously-existing Message being requested for retransmission:
Bytes | Description | Type |
---|---|---|
32 | Hash of Requested Message | Hash256 |
292 | Padding | Noise[292] |
GetData
Messages do not propagate, i.e. they may only be issued directly to a particular peer.
A GetData
Message may be emitted by a station which had received a Broadcast Text
or Direct Text
Message, and consequently found that it is suffering from a chain gap (i.e. the station is in possession of a Message for which the SelfChain
or NetChain
antecedent has not been received.
Alternatively, the station may have received a Prod
Message and learned that it had not received the most recent Broadcast Text
on its Pest Net, or the most recent Direct Text
Message a given peer had previously sent its way.
A station which receives a GetData
message may reply with a copy of the message identified by the given Hash
, if:
A station must originate a GetData
message whenever it encounters a Broadcast Text
or Direct Text
Message having a SelfChain
or NetChain
for which it does not possess the corresponding antecedent.
If the "offending" message was a Broadcast Text
, at least one GetData
request is issued to each peer of the station. If the message was a Direct Text
, at least one GetData
request must be issued to the peer from which the Direct Text
had come.
A station which is expecting a response to a GetData
request must hash every incoming Broadcast Text
or Direct Text
message, and check said hash against its list of expected hashes, prior to verifying the message's Timestamp
-- as otherwise a GetData
response bearing an older message may be deemed stale and discarded.
If the response in turn bears a SelfChain
or NetChain
for which the station does not possess an antecedent, the above logic is performed recursively on a best-effort basis.
When GetData
requests succeed in closing a chain gap, the messages in question must be displayed to the operator console in the correct order (determined by their SelfChain
or NetChain
hashes.)
If, after an operator-configured interval elapses, GetData
requests did not succeed in closing a chain gap, a warning will be issued to the operator, and the fork detector is invoked if appropriate.
If the Timestamp
of a GetData
response (or the earliest message in a chain of responses) pre-dates that of the message most recently displayed to the console, the operator must be informed of this, by prepending said Timestamp
to the text emitted to the console.
A hash of a proposed key slice. The Rekeying procedure begins with the participants exchanging Key Offer
s to demonstrate that their Key Slices
had been generated independently of one another.
The Payload
of this Message (324 bytes) consists of:
Bytes | Description | Type |
---|---|---|
64 | Hash of Key Slice to be Offered |
Hash512 |
260 | Padding | Noise[260] |
A proposed key slice. In the Rekeying procedure, after the participants have exchanged Key Offer
s and determined that they were not identical, each participant reveals his Key Slice
to the other. The procedure concludes successfully if and only if each of the slices is found to hash to its respective previously-sent Key Offer
. Their new PestKey
will equal the xor
of their previous key and both of the Key Slices
.
The Payload
of this Message (324 bytes) consists of:
Bytes | Description | Type |
---|---|---|
64 | Proposed Key Slice |
Noise[64] (Must hash to the Key Offer ) |
260 | Padding | Noise[260] |
Address Cast
messages aid in NAT penetration and eliminate the need to manually set peer Address
es (via the AT Command
) for two peers who, while unable to establish direct contact, are nonetheless able to reach a given Pest Net.
An Address Cast
Message
is a Broadcast Message
bearing a payload keyed to a particular peer: the target -- who, while at a given time not directly reachable by the sender of the Address Cast
-- may be present on the Pest Net and able to receive Broadcasts
.
An Address Cast
bears the Address
at which the sender would like to be reached by the target. The Payload
of a Black Address Cast
message resembles a Black Packet.
An Address Cast
(being a Broadcast
) is disseminated as widely as possible on the sender's Pest Net. However, it will only be meaningful to the target -- the peer whose PestKey
was chosen for the encryption and signing of the message's encrypted payload.
Address Cast
messages are only generated for a target who is presently cold, i.e. a peer from whom no valid packets have been received for at least Tc
seconds (an operator-configurable interval) or for whom at least one PestKey
is known but no AT
entry currently exists.
A station will generate and broadcast an Address Cast
message targeted to each such peer in its WOT
every Ta
seconds (an operator-configurable interval.) Ta
must be greater than or equal to Tc
.
A target which succeeds in receiving and decoding an Address Cast
will generally succeed in re-establishing direct contact with its sender.
The Payload
of the Message (324 bytes) consists of:
Bytes | Description | Type |
---|---|---|
272 | Ciphertext (created with the target's K(C)) | Ciphertext[272] |
48 | Seal (created with the target's K(S)) | Seal |
4 | Padding | Noise[4] |
The Speaker field of a Message
bearing an Address Cast
Payload
must match a WOT
handle corresponding to its apparent originator.
A station which receives an Address Cast
Message will attempt to verify and decrypt it (into a Red Address Cast
) strictly on a best-effort basis (i.e. when the CPU would otherwise be idle), and strictly if there are currently cold peers in the station's WOT
.
The logic is identical to that used for decoding Broadcast Text messages, with the exception of the epilogue, where, instead of treating the (decoded) Ciphertext
as Red Packet
, it will be interpreted as a Red Address Cast
.
A Red Address Cast is the decrypted Ciphertext of a Black Address Cast Message. It consists of 272
bytes:
Bytes | Description | Type |
---|---|---|
16 | Nonce |
Noise[16] |
4 | Cast Command | Zero[4] |
6 | Address | PestAddress |
246 | Padding | Noise[246] |
Cast Command
must equal 0
(signifying Address Cast
).
The Address
field represents the IPv4 address and port number on which the originator station wishes to receive Pest packets from the target. Typically, the originator obtains this information from a recently-received Prod
.
The supplied IP must represent a publicly-routable IPv4 address. (If a receiving station determines that it does not, it must silently reject the message.)
A station which successfully validated and decrypted an Address Cast
from a cold peer will execute an equivalent of the AT
command, and henceforth use the supplied Address
for all outgoing packets intended to reach that peer.
Upon processing a Red Address Cast
, a station will immediately transmit an unspecified (but greater than or equal to 2
) number of packets to its originator, at least one of which will carry a Prod
, with the rest bearing Ignore
(rubbish) Messages.
An Address Cast
found to have been received from a warm (i.e. not cold) peer is ignored.
A garbage message. A station may transmit garbage messages to its peers, to frustrate traffic analysis by snoops. In such cases, the Payload
will consist of arbitrary random bytes. A recipient of such a message may relay it to an arbitrary subset of his WOT
. Receipt of a garbage message must not result in any console output.
A station transmits Message
s exclusively to peers. Prior to transmission, a Message
is encoded into a red packet, which is then ciphered and signed using a PestKey
found in the WOT
for the Message
's intended addressee. Following this, the packet is referred to as black and sent on its way.
A black Pest packet consists of 496 bytes (excluding IP and UDP headers) representing the following fields:
Bytes | Description | Type |
---|---|---|
448 | Ciphertext | Ciphertext[448] |
48 | Seal | Seal |
A third party without knowledge of the key is unable to read such a packet; to distinguish it from arbitrary random noise; or to generate a spurious replacement (including via replay, in whole or in part, of a previously-sent packet) that could be accepted by the addressee.
Every incoming (without exception, black) packet has its Seal
verified against each K(S)
in the receiving station's WOT
, in random order.
If a verification of the packet against a particular K(S)
succeeds, the packet is then known to have been signed by the peer associated with that key. The packet is then decrypted (with K(C)
, the corresponding cipher key) and becomes red once again; at this point, the receiving station is able to process the Message
carried by the packet.
However, if none of the attempted verifications succeed, the packet is deemed a "martian" and silently discarded13. The receipt of a martian packet has absolutely no effect on a station, aside from wasting a small amount of CPU time. This provides a reasonable degree of DDOS resistance. A station may keep inexpensive statistical counters of martian packets.
A Pest station has three message buffers:
The Long Buffer
, aka the deduplication buffer, is a ring buffer holding at least the last hour's worth of fully processed unique Messages
(including ones originated at the station) indexed by message hash for speed of retrieval. Any incoming Message
found to have been previously interned in the Long Buffer
is rejected immediately.
The Order Buffer
temporarily interns packets bearing Broadcast Text
and Direct Text
Message
s whose SelfChain
or NetChain
value has triggered the issuance of a GetData
request. Such a packet is interned in the buffer for at most Tw
seconds (an operator-configurable interval, not in excess of 5 minutes); following which, it is released for further processing, which continues at Step 10 of the Common Prologue.
At any time when the Order Buffer
is non-empty, the station will schedule the continued processing of the oldest packet found there, to be executed Tw
seconds following the Time
at which said message was received.
The Order Buffer
may contain packets bearing duplicate messages, and is indexed by Time
of message receipt.
The Short Buffer
, aka the hearsay embargo buffer: a ring buffer holding the last Te
seconds worth of embargoed unique messages, indexed by message hash for speed of retrieval. Te
is an operator-configurable interval, known as the embargo interval (recommended: 1 second).
Each message interned in the Short Buffer
also has the following associated information:
Rm
, consisting of all peers who have supplied copies of the message during its embargo interval.Tm
, at which the earliest known copy of the message was received during its embargo interval.Bm
, representing the lowest bounce count seen among the packets bearing copies of the message.At any time when the Short Buffer
is non-empty, the station will schedule an hearsay eviction task, to be executed Te
seconds following the Tm
of the oldest message found in the buffer.
When a station operator enters a line of text into the console, creating a new Message
, that station is termed the originator of that message.
There are two forms of message origination:
Suppose that a station operator using the handle shalmaneser
had issued the command:
/PRIVMSG nebuchadnezzar Come to tea.
The following actions will be performed:
WOT
is searched for a peer with a handle nebuchadnezzar
. If there isn't one, or nebuchadnezzar
is currently paused, nothing further happens, and a warning will be emitted to the console.K
for nebuchadnezzar
is found. (If no keys are known for nebuchadnezzar
, nothing further happens, and a warning will be emitted to the console.) K
is a PestKey
, , of which the components are K(S)
(the signing key) and K(C)
(the cipher key).nebuchadnezzar
is found. (If one such does not exist... see above.)A Red Packet is created, where:
Bytes | Description | Value |
---|---|---|
16 |
Nonce |
random bytes |
1 |
Bounces |
0 |
1 |
Version |
a single byte representing the Pest protocol version supported by the originating station. |
1 |
Reserved |
0 |
1 |
Command |
0x01 (Direct Text) |
428 |
Message |
as given below: |
Bytes | Description | Value |
---|---|---|
8 |
Timestamp |
shalmaneser 's current time |
32 |
SelfChain |
hash of shalmaneser 's previous direct message to nebuchadnezzar |
32 |
NetChain |
0 |
32 |
Speaker |
shalmaneser (padded with null bytes.) |
324 |
UString[324] |
Come to tea. (padded with null bytes.) |
A Black Packet is created from the above Red Packet, where:
Bytes | Description | Value |
---|---|---|
448 | Ciphertext | SERPENT_ENCRYPT( K(C) , the 448-byte Red Packet) |
48 | Seal | HMAC384(Ciphertext, K(S) ) |
The message is interned into the station's Long Buffer
.
The Black Packet bearing the message is transmitted to nebuchadnezzar
's current AT
address, determined in step 3.
Suppose a station operator using the handle shalmaneser
had issued the command:
/PRIVMSG #pest Good morning, everyone!
The following actions will be performed:
A
, is generated. By default, it will consist of all of the peers in shalmaneser
's WOT
(with the exception of any paused peers). However, if the message is a rebroadcast, A
will not contain any peers from which copies of the message to be rebroadcast are known to have been received. For each peer P
in A
, in random order:Pk
for P
is found. (If no keys are known for P
, we move on to the next peer.) Pk
is a PestKey
, of which the components are Pk(S)
(the signing key) and Pk(C)
(the cipher key).P
is found. (If one such does not exist, we move on to the next peer.)For each P in A
, a Red Packet is created, where:
Bytes | Description | Value |
---|---|---|
16 |
Nonce |
random bytes |
1 |
Bounces |
0 |
1 |
Version |
a single byte representing the Pest protocol version supported by the originating station. |
1 |
Reserved |
0 |
1 |
Command |
0x00 (Broadcast Text) |
428 |
Message |
as given below: |
Bytes | Description | Value |
---|---|---|
8 |
Timestamp |
shalmaneser 's current time |
32 |
SelfChain |
hash of shalmaneser 's previous broadcast message |
32 |
NetChain |
hash of the previous broadcast message seen by shalmaneser , not inclusive of this one |
32 |
Speaker |
shalmaneser (padded with null bytes.) |
324 |
UString[324] |
Good morning, everyone! (padded with null bytes.) |
A Black Packet is created from the above Red Packet, where:
Bytes | Description | Value |
---|---|---|
448 | Ciphertext | SERPENT_ENCRYPT( Pk(C) , the 448-byte Red Packet) |
48 | Seal | HMAC384(Ciphertext, Pk(S) ) |
The message is interned into the station's Long Buffer
.
The above Black Packet is transmitted to its addressee (i.e. to the Address currently known via the AT
for the peer P
) as determined in step 3.
Suppose that a station operated by nebuchadnezzar
has received a packet. The packet is from shalmaneser
, but nebuchadnezzar
's station does not know this yet, it has to authenticate and decrypt it first. Since all Pest packets traveling over the public internet are black, it will have the structure:
Bytes | Description | Value |
---|---|---|
448 | Ciphertext | A Red Packet, ciphered with unknown cipher key K(C) . |
48 | Seal | The result of signing Ciphertext with an unknown signing key K(S) . |
nebuchadnezzar
's station will carry out the following procedure:
Pk
in nebuchadnezzar
's WOT
, in random order:P
represents the peer to whom the key Pk
belongs. Pk
is a PestKey
, of which the components are Pk(S)
(the signing key) and Pk(C)
(the cipher key).HMAC384(Ciphertext, Pk(S))
is compared to Seal
. If they do not match, the next one is tried. If none match, the packet is declared martian and silently discarded.Pk(C)
is used to decrypt Ciphertext
and reproduce the original Red Packet. The packet is now considered to have been sent by the station operated by peer P
.H
be the set of all handles found in the station's WOT
for the peer who was found to have sent the packet; e.g. {shalmaneser, ShalmaneserTheGreat}
.GetData
request is anticipated, the message is hashed; and if its hash is found in the list of currently-anticipated GetData
responses, the message is deemed expected, and the next step is skipped. Note, however, that GetData
responses are not to be rebroadcast.Timestamp
is compared to the current system time and if it is more than 15 minutes in the past or the future, the packet is considered stale and discarded.Speaker
of the message is present in the GAG
list, the message will not be displayed to the station's console or rebroadcast; however, it may still trigger the issuance of GetData
requests if its antecedents cannot be found in the Long Buffer
.Long Buffer
is queried for the presence of a message with said hash. If found to be present, the message is rejected as a duplicate.Broadcast Text
or Direct Text
, the Long Buffer
is searched for the message's antecedents; if these cannot be located, a GetData
request is issued. In such a case, the message will be interned in the Order Buffer
prior to further processing.Command
field...Continuing after the final step of the Common Prologue:
If Command
is equal to 0x01
, the message is a direct message:
Bounces
is not equal to 0x00
, the packet is discarded, given as direct messages are not relayed to third parties.Long Buffer
.SelfChain
warning is displayed if required.Speaker
is not in H
, the console will display the Payload
of the message in the following format, e.g. if the Speaker
is bob
, while the originator is shalmaneser
, then:
bob-shalmaneser: hello
... in the standard format for IRC private messages. (The operator of the receiving station may then choose to execute an AKA
command to store bob
as a handle sometimes used by the originator.)Speaker
is in H
, the console will display the Speaker
, followed by the Payload
, e.g:
shalmaneser: Come to tea.
... in the standard format for IRC private messages.Continuing after the final step of the Common Prologue:
If Command
is equal to 0x00
, the message is a broadcast message:
Bounces
is compared to the operator-configured cutoff. If it is in excess of the bounce cutoff, the packet bearing the message is discarded.Speaker
is in H
:If Speaker
is in H
, the message is known as an immediate message. Given as it was received directly from its originator, it is considered prima facie authentic. Continuing after the final step of 4.3.3. Receiving a Broadcast Message.:
Long Buffer
.Short Buffer
, it is immediately removed from it.Speaker
had previously been forked, the fork is immediately resolved in favour of the current message. The operator is notified in the following way, e.g.: shalmaneser-2 was shalmaneser.
Payload
of the message is displayed in nebuchadnezzar
's console in the standard form for IRC messages, marked with channel #pest
.If Speaker
is NOT in H
, the message is known as a hearsay message. This means that the message was received from a peer who was not its originator, but rather its relayer. Duplicates of the message may arrive in rapid succession from multiple relayers. It is also possible that an immediate copy of the message is still in transit and may yet be received, removing the requirement to mark the message as hearsay.
Hearsay messages are processed as follows. Continuing after the final step of 4.3.3. Receiving a Broadcast Message.:
Bounces
is equal to 0x00
, the message is discarded, given as only an immediate broadcast message may have a bounce of zero.Short Buffer
.Short Buffer
until its eviction (either after the elapse of its eviction interval, or upon the receipt of an immediate copy of the message directly from its originator.Upon the elapse of Te
seconds after a hearsay message's Tm
(the time at which the earliest known copy was received), the following takes place:
The message is interned into the Long Buffer
.
The message is removed from the Short Buffer
.
The message's Rm
is considered to be a complete list of its relayers, i.e. peers who supplied copies of the message during the interval Tm
... Tm + Te
.
The message's Bm
is considered to be the the minimum of all of the bounce counts among the copies received.
A subset of Rm
, Rbm
, is determined. It consists of such members of Rm
whose packet's bounce count was equal to Bm
.
The message is relayed to all active WOT
peers, other than those found in Rm
. The bounce count in the emitted packets will equal Bm + 1
.
The Payload
of the message is displayed to the station operator's console in one of the two following formats, depending on the number of entries in Rbm
:
If Rbm
consists of three or fewer peers, the Payload
of the message is displayed in the console preceded by a set of square brackets listing the members of Rbm
.
For instance, if min-bounce copies of a hearsay message purporting to originate from hammurabi
had been received from shalmaneser
, nebuchadnezzar
, and bob
, the list of these relayers will appear in square brackets, separated by |
(pipe) characters:
hammurabi[shalmaneser|nebuchadnezzar|bob]: hi there
But if Rbm
contains four or more members, the brackets will instead contain simply their total number:
hammurabi[11]: hi
All symmetric cipher keys "age" with use. A Pest station may send Rekey
requests to a particular peer. The receiving station may process such requests, or silently reject them.
It is recommended that a Rekey
be conducted immediately after an initial peering and at regular intervals thereafter. Station operators may disable the processing of incoming Rekey
requests (see the RKTOG
control command) to preserve the validity of scheduled WOT
backups; and re-enable it, when necessary, by mutual verbal agreement.
The Pest rekeying process is such that the initiator and receiver are each required to generate a xor-slice of the proposed new PestKey
Kn
independently. The new key will be equal to the xor
of the previous key K
shared by the two peers, with both of the proposed slices: Kn == K xor Sa xor Sb
. Consequently, the new key Kn
will have an expected entropy greater than or equal to that of the old key K
and each of the slices Sa
, Sb
.
The algorithm takes the following form:
A
would like to rekey with its peer B
, and generates a 512-bit Key Slice
Sa
using its TRNG. It takes a 512-bit hash of Sa
and encodes it into a Key Offer
Message
, which is then transmitted to station B
.B
receives A
's Key Offer
. If rekeying is enabled on station B
, it will proceed with the rekeying algorithm; otherwise it will silently discard the offer packet, and nothing further happens. If A
does not receive the answer defined in the next step, it may try again in the future (given as the packet may have been lost in transit.)B
chooses to accept A
's Key Offer
, it will generate its own slice, Sb
, produce a Key Offer
as described in the two preceding steps, and transmit said offer to station A
.A
receives B
's Key Offer
, it will verify that the latter does not equal its own previously-sent Key Offer
. (If they were found to be identical, B
's Key Offer
is deemed invalid, and A
will abort the rekeying.) If A
proceeds with the rekeying, it will now encode its slice Sa
into a Key Slice
Message
and transmit said Message
to station B
.B
will determine whether the hash in A
's Key Offer
corresponds to H(Sa)
where H
is the hash function. If it does not, the offer is deemed invalid and station B
carries on as before, as if no rekeying request had been made.B
will reply by similarly encoding its slice Sb
into a Key Slice
Message
and transmitting said Message
to station A
.B
is able to calculate the new key Kn
using the equation: Kn == K xor Sa xor Sb
where K
is the previous key used for peer A
, Sa
is A
's Key Slice
, and Sb
is B
's Key Slice
. B
records this key in its WOT
entry for A
, but does not discard the old key K
yet.A
will perform the same comparison operation as described in step 5. If the hash does not match, B
's offer is deemed invalid, and nothing further happens.Rekey
handshake is deemed successful.A
will calculate the new key Kn
, similarly to B
in step 7: Kn == K xor Sa xor Sb
where K
is the previous key shared with peer B
, Sa
is A
's Key Slice
, and Sb
is B
's Key Slice
. A
records this key in its WOT
entry for B
, but does not discard the old key K
yet.A
will transmit an Ignore
packet to station B
using the new key Kn
.B
, upon receiving this packet, will succeed in decoding it using Kn
. It will reply with an Ignore
packet to station A
, ciphered and signed using Kn
.Kn
to their WOT
s under the entry for the respective peer.Kn
, the old shared key of the peers K
(with which they carried out steps 1 through 8) will be retired and removed from each station's WOT
.All communication in steps 1 through 9 takes place using the previously-known shared key K
.
A rekeying is deemed to have aborted (any slice Sx
, as well as Kn
if it has been generated -- discarded by the station) if it does not complete within an operator-specified interval Tk
.
A station which has successfully rekeyed a peer (regardless of which operator initiated the rekeying process) will warn its operator, so that he is made aware of the need to back up his WOT
.
A Pest station trapped behind a NAT (Network Address Translation) apparatus may at first find itself unreachable by peers located outside of it. Pest offers a simple NAT penetration mechanism which enables a station to "escape" from the NAT, without access to the latter's configuration -- supposing that it is able to communicate with at least one peer in its WOT
who is not inside a NAT, or has already succeeded in similarly escaping from his NAT.
T
, trapped behind a NAT, which is able to establish a bidirectional flow of packets with at least one peer P
(via use of the AT
command) will succeed in transmitting a Prod
to P
.P
immediately replies to T
with another Prod
(most NATs will pass an immediate reply to a UDP packet's address and port of origin), informing T
of T
's own externally-reachable IP and port A
, i.e. a PestAddress
at which T
can be reached.A
will be a random ephemeral port "temporarily" assigned by T
's NAT, and the IP of A
will be the publicly-routed IP via which T
's NAT exits to the Internet at large.T
then periodically generates Address Cast
Messages
targeted to its still-unreachable peers, requesting to be contacted at A
, and transmits them to P
.P
will relay the Address Cast
s to the Pest Net, where they will propagate, eventually reaching other peers of T
.T
's still-unreachable peers receives and processes the Address Cast
Message targeted to it, it will begin sending packets to A
.T
will now succeed in establishing a bidirectional flow of packets with each of these peers.T
will keep the ephemeral ports in the NAT's routing table alive by issuing Ignore
messages to each of its peers every Ti
seconds (an operator-adjustable interval, with a recommended value of no more than 10
seconds).PestAddress
for each of its peers.This mechanism also eliminates the need to manually configure (via the AT
command) a PestAddress
for a newly-added peer who was already an inhabitant of your Pest Net.
A freshly-booted Pest station will assume that it is trapped behind a NAT. (If this is not so, in fact no change is required in the above algorithm, and the station will function normally, while helping any "trapped" peers to escape their NATs.)
The base64-encoded PestKey
:
2Newlil7CEAcrLlLJhJaX1bOhYMzhbzX5s/UPYGXM3xTTry7sqvwYyp6ffinpQmgVVKZahjgIGILrPcAH2oI6A==
... when correctly decoded and broken into two 256-bit segments, represents the following (shown here in base-16) signing key:
d8d7b096297b08401cacb94b26125a5f56ce85833385bcd7e6cfd43d8197337c
... and the following cipher key:
534ebcbbb2abf0632a7a7df8a7a509a05552996a18e020620bacf7001f6a08e8
The base64-encoded PestKey
:
DpLg4cXUoraDQHaSfScfO7rV4jJGDKvq1RkpSnHRKKhhCZXMSvaq6QGKgcAbYriNXsw0bdiiz2/M0VeKL1Cb6g==
... when correctly decoded and broken into two 256-bit segments, represents the following (shown here in base-16) signing key:
0e92e0e1c5d4a2b6834076927d271f3bbad5e232460cabead519294a71d128a8
... and the following cipher key:
610995cc4af6aae9018a81c01b62b88d5ecc346dd8a2cf6fccd1578a2f509bea
TBD
Serpent
, in Cipher Block Chaining (CBC) mode, is the only symmetric cipher to be used.
All Seals are generated and verified with HMAC-384
.
All byte ordering in Pest, without exception, is little-endian unless otherwise stated.
If an operator wishes to run bots, guest accounts, etc., additional stations may be set up to peer with his primary one; on the same physical machine, if so desired.
When provisioning hardware for a Pest station, the operator must provide sufficient CPU cores, so that it may:
The processing of ICMP packets by a machine housing a Pest station exposes the latter to demasking, violating the nothing to the stranger dictum; it is also a traditional DDOS vector. Therefore it is recommended that Pest station operators disable the processing of ICMP packets under any pretext whatsoever by whatever means required under their operating system or firewall setup.
For instance, a provocateur displaying your purported thoughtcrimes to his handler. (See e.g. this discussion of the basics.) ↩
Of course, Pest does not somehow prevent operators from creating opposably-signed messages using other software and transmitting them to their peers, on the rare occasions which actually call for this. ↩
Since only a valid packet will invoke any response from a Pest station, a stranger cannot -- via any heuristic whatsoever -- determine whether a certain remote IP address is in use by a certain Pest station; or whether a given set of IP addresses may belong to the same Pest station, or to a group of Pest peers; or, for that matter, whether they pertain to any use of Pest at all. It is impossible to port scan for Pest stations. A well-configured station will not use IP addresses shared with any public Internet services (e.g. WWW) for Pest; and will not answer ICMP messages sent to such addresses. Consequently, a stranger is not able to determine whether there even exists a machine at any such address. In other words, an IP address used by a Pest station is, from the point of view of anyone other than a peer of that station, indistinguishable from one assigned to an unplugged machine. ↩
Or, for that matter, one which may not have been intended as a Pest packet at all -- but simply happens to consist of 496 bytes. ↩
However, sometimes it is necessary to count the number of distinct peers who provided copies of a given message. ↩
Via secure means external to Pest, such as GPG, Peh, or an in-person meeting. ↩
A K
is to be generated using a TRNG whenever possible. Multiple keys associated with one peer are permitted. This is convenient when phasing out an old key in favour of a new one. The converse (the use of one key for multiple peers) is prohibited. When addressing outgoing packets to a peer for whom multiple values of K
are known, the one which validated the most recently-received packet is to be used. ↩
That is, the source address of the most recent packet received from this peer. ↩
Current time shall be defined as the value of a station's 64-bit monotonic epoch clock, traditionally defined as "a 64-bit unsigned fixed-point number, in seconds relative to 00:00:00 January 1, 1970, UTC". Station operators must take measures to synchronize their clocks within 15 minutes, a precision entirely achievable without recourse to centralized time servers. ↩
In the current protocol: SHA256. The hash encompasses all message fields, in the order they are listed in the table. Any trailing padding bytes required by the hash are to equal zero. ↩
Americanism. ↩
All discarded packets are discarded silently; at no point is there to be any response to an invalid packet. ↩