aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortrevnoise <noise@trevp.net>2017-05-10 06:41:35 +0000
committertrevnoise <noise@trevp.net>2017-05-10 06:41:35 +0000
commit903ea3f7ed684f2f9e53d246e77d1acbd781d48a (patch)
tree6ab27ace2e3e33146073484d25a848f536d627f2
parentMinor text tweaks (diff)
downloadnoise-rev32.tar.xz
noise-rev32.zip
Book1 / Book2rev32
-rw-r--r--Makefile10
-rw-r--r--my.bib12
-rw-r--r--noise.md78
-rw-r--r--noise_book2.md341
-rw-r--r--output/noise.html100
-rw-r--r--output/noise.pdfbin353192 -> 350650 bytes
-rw-r--r--output/noise_book2.pdfbin0 -> 238243 bytes
7 files changed, 423 insertions, 118 deletions
diff --git a/Makefile b/Makefile
index 8f010d0..7a25e1d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-default: output/noise.html output/noise.pdf
+default: output/noise.html output/noise.pdf output/noise_book2.pdf
# Pandoc 1.17.2, Pandoc-citeproc
@@ -18,5 +18,11 @@ output/noise.pdf: noise.md template_pandoc.latex my.bib
--filter pandoc-citeproc \
-o output/noise.pdf
+output/noise_book2.pdf: noise_book2.md template_pandoc.latex my.bib
+ pandoc noise_book2.md -s --toc \
+ -f markdown\
+ --template template_pandoc.latex \
+ --filter pandoc-citeproc \
+ -o output/noise_book2.pdf
clean:
- rm output/noise.html output/noise.pdf
+ rm output/noise.html output/noise.pdf output/noise_book2.pdf
diff --git a/my.bib b/my.bib
index 7c8db8d..e9b78d0 100644
--- a/my.bib
+++ b/my.bib
@@ -230,6 +230,18 @@ https://moderncrypto.org/mail-archive/noise/2015/000098.html
url = "http://eprint.iacr.org/2017/003",
}
+@misc{book1,
+ author = "{Trevor Perrin}",
+ title = "{The Noise Protocol Framework: Book 1}",
+ year = {2017},
+ url = "https://noiseprotocol.org/noise_book1.pdf",
+}
+@misc{book2,
+ author = "{Trevor Perrin}",
+ title = "{The Noise Protocol Framework: Book 2}",
+ year = {2017},
+ url = "https://noiseprotocol.org/noise_book2.pdf",
+}
diff --git a/noise.md b/noise.md
index 432c249..4c4a2e4 100644
--- a/noise.md
+++ b/noise.md
@@ -1,8 +1,8 @@
---
-title: 'Noise Protocol Framework: Core Specification'
+title: 'The Noise Protocol Framework: Book 1'
author: 'Trevor Perrin (noise@trevp.net)'
revision: '32draft'
-date: '2017-04-07'
+date: '2017-05-09'
bibliography: 'my.bib'
link-citations: 'true'
csl: 'ieee-with-url.csl'
@@ -13,7 +13,11 @@ csl: 'ieee-with-url.csl'
Noise is a framework for crypto protocols based on Diffie-Hellman key
agreement. Noise can describe protocols that consist of a single message as
-well as interactive protocols.
+well as interactive protocols.
+
+This document is the first of two books which provide the specification for
+Noise. This document can be read as a self-contained specification, however
+Book 2 adds features that are important in many use cases.
2. Overview
============
@@ -260,9 +264,6 @@ Noise depends on the following **cipher functions**:
data `ad`. Returns the plaintext, unless authentication fails, in which
case an error is signaled to the caller.
- * **`REKEY(k)`**: Returns a new 32-byte cipher key as a pseudorandom function
- of `k`. If this function is not specifically defined for some set of cipher functions, then it defaults to returning the first 32 bytes from `ENCRYPT(k, maxnonce, zerolen, zeros)`, where `MAXNONCE` equals 2^64^-1, `zerolen` is a zero-length byte sequence, and `zeros` is a sequence of 32 bytes filled with zeros.
-
4.3. Hash functions
--------------------
@@ -282,9 +283,9 @@ Noise depends on the following **hash function** (and associated constants):
Noise defines additional functions based on the above `HASH()` function:
* **`HMAC-HASH(key, data)`**: Applies `HMAC` from [@rfc2104]
- using the `HASH()` function. This function is only called as part of `HKDF()`, below.
+ using the `HASH()` function. This function is only called as part of `HKDF2()`, below.
- * **`HKDF(chaining_key, input_key_material)`**: Takes a `chaining_key` byte
+ * **`HKDF2(chaining_key, input_key_material)`**: Takes a `chaining_key` byte
sequence of length `HASHLEN`, and an `input_key_material` byte sequence with
length either zero bytes, 32 bytes, or `DHLEN` bytes. Returns a pair of byte sequences each of length `HASHLEN`, as follows:
* Sets `temp_key = HMAC-HASH(chaining_key, input_key_material)`.
@@ -293,7 +294,7 @@ Noise defines additional functions based on the above `HASH()` function:
* Returns (output1, output2).
Note that `temp_key`, `output1`, and `output2` are all `HASHLEN` bytes in
- length. Also note that the `HKDF()` function is simply `HKDF` from [@rfc5869]
+ length. Also note that the `HKDF2()` function is simply `HKDF` from [@rfc5869]
with the `chaining_key` as HKDF `salt`, and zero-length HKDF `info`.
5. Processing rules
@@ -356,17 +357,14 @@ variables:
A `CipherState` responds to the following methods. The `++` post-increment
operator applied to `n` means "use the current `n` value, then increment it".
-The maximum `n` value (2^64^-1) is reserved for rekey (see [Section
-4.2](#cipher-functions) and [Section 9.3](#rekey)) and must not be used. If
-incrementing `n` results in 2^64^-1, then any further `EncryptWithAd()` or
-`DecryptWithAd()` calls will signal an error to the caller.
+The maximum `n` value (2^64^-1) is reserved for other use. If incrementing `n`
+results in 2^64^-1, then any further `EncryptWithAd()` or `DecryptWithAd()`
+calls will signal an error to the caller.
* **`InitializeKey(key)`**: Sets `k = key`. Sets `n = 0`.
* **`HasKey()`**: Returns true if `k` is non-empty, false otherwise.
- * **`Rekey()`**: Sets `k = REKEY(k)`.
-
* **`EncryptWithAd(ad, plaintext)`**: If `k` is non-empty returns
`ENCRYPT(k, n++, ad, plaintext)`. Otherwise returns `plaintext`.
@@ -399,7 +397,7 @@ A `SymmetricState` responds to the following methods:
* **`MixKey(input_key_material)`**: Executes the following steps:
- * Sets `ck, temp_k = HKDF(ck,input_key_material)`.
+ * Sets `ck, temp_k = HKDF2(ck,input_key_material)`.
* If `HASHLEN` is 64, then truncates `temp_k` to 32 bytes.
* Calls `InitializeKey(temp_k)`.
@@ -416,7 +414,7 @@ A `SymmetricState` responds to the following methods:
* **`Split()`**: Returns a pair of `CipherState` objects for encrypting
transport messages. Executes the following steps, where `zerolen` is a zero-length
byte sequence:
- * Sets `temp_k1, temp_k2 = HKDF(ck, zerolen)`.
+ * Sets `temp_k1, temp_k2 = HKDF2(ck, zerolen)`.
* If `HASHLEN` is 64, then truncates `temp_k1` and `temp_k2` to 32 bytes.
* Creates two new `CipherState` objects `c1` and `c2`.
* Calls `c1.InitializeKey(temp_k1)` and `c2.InitializeKey(temp_k2)`.
@@ -481,8 +479,6 @@ A `HandshakeState` responds to the following methods:
* Sets `message_patterns` to the message patterns from `handshake_pattern`.
-\newpage
-
* **`WriteMessage(payload, message_buffer)`**: Takes a `payload` byte sequence
which may be zero-length, and a `message_buffer` to write the output into. Performs the following steps:
@@ -1216,20 +1212,6 @@ To support this, Noise libraries should expose the final value of h to the appli
Parties can then sign the handshake hash, or hash it along with their password, to get an authentication token which has a "channel binding" property: the token can't be used by the receiving party with a different sesssion.
-9.3. Rekey
------------
-Parties might wish to periodically call the `Rekey()` function on their transport cipherstates, so that a compromise of cipherstate keys will not decrypt older messages. Periodic rekey might also be used to reduce the volume of data encrypted under a single cipher key (this is usually not important with good ciphers, though note the discussion on `AESGCM` data volumes in [Section 13](#security-considerations) ).
-
-It is up to to the application if and when to perform rekey. For example:
-
- * Applications might perform continuous rekey, where they rekey the relevant cipherstate after every transport message sent or received. This is simple and gives good protection to older ciphertexts, but might be difficult for implementations where changing keys is expensive.
-
- * Applications might rekey a cipherstate automatically after it has has been used to send or receive some number of messages.
-
- * Applications might choose to rekey based on arbitrary criteria, in which case they signal this to the other party by sending a message.
-
-Note that rekey doesn't reset the cipherstate's `n` value, so applications performing rekey must still perform a new handshake if sending 2^64^ or more transport messages.
-
10. DH functions, cipher functions, and hash functions
======================================================
@@ -1314,8 +1296,6 @@ Note that rekey doesn't reset the cipherstate's `n` value, so applications perfo
* **`HASHLEN`** = 64
* **`BLOCKLEN`** = 128
-\newpage
-
11. Protocol names
===================
@@ -1392,9 +1372,10 @@ This section collects various security considerations:
with a pre-message public key and assume that a successful handshake implies
the other party's knowledge of the public key. Unfortunately, this is not
the case, since setting public keys to invalid values might cause
- predictable DH output. For example, a `Noise_NK_25519` initiator might
- send an invalid ephemeral public key to cause a known DH output of all
- zeros, despite not knowing the responder's static public key.
+ predictable DH output. For example, a `Noise_NK_25519` initiator might send
+ an invalid ephemeral public key to cause a known DH output of all zeros,
+ despite not knowing the responder's static public key. If the parties want
+ to authenticate with a shared secret, it should be used as a "PSK" [@book2].
* **Channel binding**: Depending on the DH functions, it might be possible
for a malicious party to engage in multiple sessions that derive the same
@@ -1408,9 +1389,8 @@ This section collects various security considerations:
* **Incrementing nonces**: Reusing a nonce value for `n` with the same key
`k` for encryption would be catastrophic. Implementations must carefully
follow the rules for nonces. Nonces are not allowed to wrap back to zero
- due to integer overflow, and the maximum nonce value is reserved for
- rekeying. This means parties are not allowed to send more than 2^64^-1
- transport messages.
+ due to integer overflow, and the maximum nonce value is reserved. This
+ means parties are not allowed to send more than 2^64^-1 transport messages.
* **Fresh ephemerals**: Every party in a Noise protocol should send a new
ephemeral public key and perform a DH with it prior to sending any encrypted
@@ -1430,8 +1410,7 @@ This section collects various security considerations:
in security as the volume of data encrypted under a single key increases.
Due to this, parties should not send more than 2^56^ bytes (roughly 72
petabytes) encrypted by a single key. If sending such large volumes of data
- is a possibility then different cipher functions should be chosen, or the
- cipherstate should be rekeyed ([Section 9.3](#rekey)) before this limit is reached.
+ is a possibility then different cipher functions should be chosen.
* **Hash collisions**: If an attacker can find hash collisions on prologue
data or the handshake hash, they may be able to perform "transcript
@@ -1500,17 +1479,6 @@ Cipher nonces are big-endian for `AESGCM`, and little-endian for `ChaCha20`, bec
* It makes sense to use consistent endianness in the cipher code.
-Rekey defaults to using encryption with the nonce 2^64^-1 because:
-
- * With `AESGCM` and `ChaChaPoly` rekey can be computed efficiently (the "encryption" just needs to apply the cipher, and can skip calculation of the authentication tag).
-
-Rekey doesn't reset the nonce `n` to zero because:
-
- * Leaving `n` unchanged is simple.
-
- * If the cipher has a weakness such that repeated rekeying gives rise to a cycle of keys, then letting `n` advance will avoid catastrophic reuse of the same `k` and `n` values.
-
- * Letting `n` advance puts a bound on the total number of encryptions that can be performed with a set of derived keys.
14.2. Hash functions and hashing
--------------
@@ -1620,7 +1588,7 @@ Explicit random nonces (like TLS "Random" fields) are not used because:
15. IPR
========
-The Noise specification (this document) is hereby placed in the public domain.
+The Noise specification Book 1 (this document) is hereby placed in the public domain.
16. Acknowledgements
=====================
diff --git a/noise_book2.md b/noise_book2.md
new file mode 100644
index 0000000..d4a9b66
--- /dev/null
+++ b/noise_book2.md
@@ -0,0 +1,341 @@
+---
+title: 'The Noise Protocol Framework: Book 2'
+author: 'Trevor Perrin (noise@trevp.net)'
+revision: '0draft'
+date: '2017-05-09'
+bibliography: 'my.bib'
+link-citations: 'true'
+csl: 'ieee-with-url.csl'
+---
+
+1. Introduction
+================
+
+Noise is a framework for crypto protocols based on Diffie-Hellman key
+agreement. This specification defines additional features that can be used
+in combination with the features defined in Book 1 [@book1].
+
+2. Modifiers
+=============
+To specify extensions or modifications to the behavior in Book 1 [@book1], Noise uses **modifiers**.
+
+A modifier is an ASCII string which is added to some component of the Noise
+protocol name. A modifier can be a **pattern modifier**, **DH modifier**,
+**cipher modifier**, or **hash modifier**, depending on which component of the
+protocol name it is added to.
+
+The first modifier added onto a base name is simply appended. Thus, `fallback`
+is a pattern modifier added to the `XX` base name to produce `XXfallback`.
+Additional modifiers are separated with a plus sign. Thus, adding the `psk0`
+pattern modifier (below) would result in the pattern name `XXfallback+psk0`.
+
+The final protocol name, including all modifiers, must be less than or equal to 255
+bytes (e.g. `Noise_XXfallback+psk0_25519_AESGCM_SHA256`).
+
+3. Pre-shared symmetric keys (PSK)
+============
+
+Noise provides a **pre-shared symmetric key** or **PSK** mode to
+support protocols where both parties have a shared secret key. When
+using PSK mode, the following changes are made:
+
+3.1. Cryptographic functions
+----------------------------------
+
+An additional function is defined based on the `HASH()` function:
+
+ * **`HKDF3(chaining_key, input_key_material)`**: Takes a `chaining_key` byte
+ sequence of length `HASHLEN`, and an `input_key_material` byte sequence with
+ length of 32 bytes or `DHLEN` bytes. Returns a triple of byte sequences each of length `HASHLEN`:
+ * Sets `temp_key = HMAC-HASH(chaining_key, input_key_material)`.
+ * Sets `output1 = HMAC-HASH(temp_key, byte(0x01))`.
+ * Sets `output2 = HMAC-HASH(temp_key, output1 || byte(0x02))`.
+ * Sets `output3 = HMAC-HASH(temp_key, output2 || byte(0x03))`.
+ * Returns `(output1, output2, output3)`.
+
+Note that `temp_key`, `output1`, `output2`, and `output3` are all `HASHLEN`
+bytes in length. Also note that the `HKDF3()` function is identical to `HKDF2()`
+from [@book1] except that a third output is produced.
+
+An additional function is also defined in the `SymmetricState` object:
+
+\newpage
+
+ * **`MixKeyAndHash(input_key_material)`**: Executes the following steps:
+
+ * Sets `ck, temp_h, temp_k = HKDF3(ck, input_key_material)`.
+ * Calls `MixHash(temp_h)`.
+ * If `HASHLEN` is 64, then truncates `temp_k` to 32 bytes.
+ * Calls `InitializeKey(temp_k)`.
+
+This function combines the functionality of `MixKey()` and `MixHash()` from [@book1]. Unlike those, this function ensures that
+its input affects both the encryption keys and the `h` value.
+
+The third output from `HKDF3()` is used as the `k` value so that
+calculation of `k` may be skipped if `k` is not used.
+
+3.2. Handshake tokens
+-------------------------------
+
+To support PSKs, a new `"psk"` token is allowed to appear once (or multiple
+times) in a handshake pattern. This token can only appear in message patterns
+(not pre-message patterns). This token is processed by calling
+`MixKeyAndHash(psk)`, where `psk` is a 32-byte secret value provided by the
+application.
+
+In [@book1], the `"e"` token in a pre-message pattern or message pattern always
+results in a call to `MixHash(e.public_key)`. When PSKs are used, all of these calls
+are replaced with `MixKeyAndHash(e.public_key)`. In conjunction with the validity rule in the
+next section, this ensures that PSK-based encryption uses encryption keys that are randomized using
+ephemeral public keys as nonces.
+
+3.3. Validity rule
+--------------------
+
+To prevent catastrophic key reuse, handshake patterns using the `"psk"` token must follow an additional validity rule:
+
+ * A party may not send any encrypted data after it processes a `"psk"` token unless it has previously
+ sent an ephemeral public key (an `"e"` token), either before or after the `"psk"` token.
+
+This rule guarantees that a `k` derived from a PSK will never be used for
+encryption unless it has also been randomized by `MixKeyAndHash(e.public_key)`
+using a self-chosen ephemeral public key.
+
+3.4. Pattern modifiers
+------------
+
+To indicate PSK mode and the placement of the `"psk"` token, pattern modifiers
+are used (see [Section 2](#modifiers)). The modifier `psk0` places a `"psk"`
+token at the beginning of the first handshake message. The modifiers
+`psk1`, `psk2`, etc., place a `"psk"` token at the end of the
+first, second, etc., handshake message.
+
+Any pattern using one of these modifiers must process tokens according to the rules in [Section 3.2](#-handshake-tokens]), and must follow the validity rule in [Section 3.3](#validity-rule).
+
+The table below lists some unmodified one-way patterns on the left, and the recommended
+PSK pattern on the right:
+
+
++--------------------------------+--------------------------------------+
+| Noise_N(rs): | Noise_Npsk0(rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es | -> psk, e, es |
+| | |
++--------------------------------+--------------------------------------+
+| Noise_K(s, rs): | Noise_Kpsk0(s, rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es, ss | -> psk, e, es, ss |
+| | |
++--------------------------------+--------------------------------------+
+| Noise_X(s, rs): | Noise_Xpsk1(s, rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es, s, ss | -> e, es, s, ss, psk |
+| | |
++--------------------------------+--------------------------------------+
+
+Note that the `psk1` modifier is recommended for `Noise_X`. This is because
+`Noise_X` transmits the initiator's static public key. Because PSKs are
+typically pairwise, the responder likely cannot determine the PSK until it has
+decrypted the initiator's static public key. Thus, `psk1` is likely to be more
+useful here than `psk0`.
+
+Following similar logic, we can define the most likely interactive PSK patterns:
+
+
++--------------------------------+--------------------------------------+
+| Noise_NN(): | Noise_NNpsk0(): |
+| -> e | -> psk, e |
+| <- e, ee | <- e, ee |
++--------------------------------+--------------------------------------+
+| Noise_NN(): | Noise_NNpsk2(): |
+| -> e | -> e |
+| <- e, ee | <- e, ee, psk |
++--------------------------------+--------------------------------------+
+| Noise_NK(rs): | Noise_NKpsk0(rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es | -> psk, e, es |
+| <- e, ee | <- e, ee |
++--------------------------------+--------------------------------------+
+| Noise_NK(rs): | Noise_NKpsk2(rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es | -> e, es |
+| <- e, ee | <- e, ee, psk |
++--------------------------------+--------------------------------------+
+| Noise_NX(rs): | Noise_NXpsk2(rs): |
+| -> e | -> e |
+| <- e, ee, s, es | <- e, ee, s, es, psk |
++--------------------------------+--------------------------------------+
+| Noise_XN(s): | Noise_XNpsk3(s): |
+| -> e | -> e |
+| <- e, ee | <- e, ee |
+| -> s, se | -> s, se, psk |
++--------------------------------+--------------------------------------+
+| Noise_XK(s, rs): | Noise_XKpsk3(s, rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es | -> e, es |
+| <- e, ee | <- e, ee |
+| -> s, se | -> s, se, psk |
++--------------------------------+--------------------------------------+
+| Noise_XX(s, rs): | Noise_XXpsk3(s, rs): |
+| -> e | -> e |
+| <- e, ee, s, es | <- e, ee, s, es |
+| -> s, se | -> s, se, psk |
++--------------------------------+--------------------------------------+
+| Noise_KN(s): | Noise_KNpsk0(s): |
+| -> s | -> s |
+| ... | ... |
+| -> e | -> psk, e |
+| <- e, ee, se | <- e, ee, se |
++--------------------------------+--------------------------------------+
+| Noise_KN(s): | Noise_KNpsk2(s): |
+| -> s | -> s |
+| ... | ... |
+| -> e | -> e |
+| <- e, ee, se | <- e, ee, se, psk |
++--------------------------------+--------------------------------------+
+| Noise_KK(s, rs): | Noise_KKpsk0(s, rs): |
+| -> s | -> s |
+| <- s | <- s |
+| ... | ... |
+| -> e, es, ss | -> psk, e, es, ss |
+| <- e, ee, se | <- e, ee, se |
++--------------------------------+--------------------------------------+
+| Noise_KK(s, rs): | Noise_KKpsk2(s, rs): |
+| -> s | -> s |
+| <- s | <- s |
+| ... | ... |
+| -> e, es, ss | -> e, es, ss |
+| <- e, ee, se | <- e, ee, se, psk |
++--------------------------------+--------------------------------------+
+| Noise_KX(s, rs): | Noise_KXpsk2(s, rs): |
+| -> s | -> s |
+| ... | ... |
+| -> e | -> e |
+| <- e, ee, se, s, es | <- e, ee, se, s, es, psk |
++--------------------------------+--------------------------------------+
+| Noise_IN(s): | Noise_INpsk1(s): |
+| -> e, s | -> e, s, psk |
+| <- e, ee, se | <- e, ee, se |
+| | |
++--------------------------------+--------------------------------------+
+| Noise_IN(s): | Noise_INpsk2(s): |
+| -> e, s | -> e, s |
+| <- e, ee, se | <- e, ee, se, psk |
+| | |
++--------------------------------+--------------------------------------+
+| Noise_IK(s, rs): | Noise_IKpsk1(s, rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es, s, ss | -> e, es, s, ss, psk |
+| <- e, ee, se | <- e, ee, se |
+| | |
++--------------------------------+--------------------------------------+
+| Noise_IK(s, rs): | Noise_IKpsk2(s, rs): |
+| <- s | <- s |
+| ... | ... |
+| -> e, es, s, ss | -> e, es, s, ss |
+| <- e, ee, se | <- e, ee, se, psk |
+| | |
++--------------------------------+--------------------------------------+
+| Noise_IX(s, rs): | Noise_IXpsk2(s, rs): |
+| -> e, s | -> e, s |
+| <- e, ee, se, s, es | <- e, ee, se, s, es, psk |
+| | |
++--------------------------------+--------------------------------------+
+
+Of course, the above list does not exhaust all possible patterns that can be
+formed with these modifiers, nor does it exhaust all the ways that `"psk"`
+tokens could be used outside of these modifiers (e.g. multiple PSKs per
+handshake). Defining additional PSK patterns is outside the scope of this
+document.
+
+
+4. Rekey
+===========
+
+Parties might wish to periodically update their cipherstate keys using a one-way function, so that a compromise of cipherstate keys will not decrypt older messages. Periodic rekey might also be used to reduce the volume of data encrypted under a single cipher key (this is usually not important with good ciphers, though note the discussion on `AESGCM` data volumes in Section 14 of [@book1]).
+
+To enable this, Noise supports a `Rekey()` function which may be called on a `CipherState`.
+
+It is up to to the application if and when to perform rekey. For example:
+
+ * Applications might perform continuous rekey, where they rekey the relevant cipherstate after every transport message sent or received. This is simple and gives good protection to older ciphertexts, but might be difficult for implementations where changing keys is expensive.
+
+ * Applications might rekey a cipherstate automatically after it has has been used to send or receive some number of messages.
+
+ * Applications might choose to rekey based on arbitrary criteria, in which case they signal this to the other party by sending a message.
+
+Applications must make these decisions on their own; there are no modifiers which specify rekey behavior.
+
+Note that rekey only updates the cipherstate's `k` value, it doesn't reset the cipherstate's `n` value, so applications performing rekey must still perform a new handshake if sending 2^64^ or more transport messages.
+
+4.1. Cryptographic functions
+----------------------------------
+
+To support rekey, an additional cipher function is defined:
+
+ * **`REKEY(k)`**: Returns a new 32-byte cipher key as a pseudorandom function
+ of `k`. If this function is not specifically defined for some set of cipher
+ functions, then it defaults to returning the first 32 bytes from `ENCRYPT(k,
+ maxnonce, zerolen, zeros)`, where `MAXNONCE` equals 2^64^-1, `zerolen` is a
+ zero-length byte sequence, and `zeros` is a sequence of 32 bytes filled with
+ zeros.
+
+An additional function is defined in the `CipherState` object:
+
+ * **`Rekey()`**: Sets `k = REKEY(k)`.
+
+
+5. Security Considerations
+============================
+
+ * **Pre-shared symmetric keys**: Pre-shared symmetric keys must be secret
+ values with 256 bits of entropy.
+
+6. Rationales
+==============
+
+This section collects various design rationales.
+
+5.1. Ciphers and encryption
+--------------
+
+Pre-shared symmetric keys are 256 bits because:
+
+ * Pre-shared key length is fixed to simplify testing and implementation, and
+ to deter users from mistakenly using low-entropy passwords as pre-shared keys.
+
+Rekey defaults to using encryption with the nonce 2^64^-1 because:
+
+ * With `AESGCM` and `ChaChaPoly` rekey can be computed efficiently (the "encryption" just needs to apply the cipher, and can skip calculation of the authentication tag).
+
+Rekey doesn't reset `n` to zero because:
+
+ * Leaving `n` unchanged is simple.
+
+ * If the cipher has a weakness such that repeated rekeying gives rise to a cycle of keys, then letting `n` advance will avoid catastrophic reuse of the same `k` and `n` values.
+
+ * Letting `n` advance puts a bound on the total number of encryptions that can be performed with a set of derived keys.
+
+
+7. IPR
+========
+
+The Noise specification Book 2 (this document) is hereby placed in the public domain.
+
+8. Acknowledgements
+=====================
+
+The PSK approach was largely motivated and designed by Jason Donenfeld, based on his experience with PSKs in WireGuard.
+
+The rekey design benefited from discussions with Rhys Weatherley, Alexey Ermishkin, and Olaoluwa Osuntokun.
+
+
+9. References
+================
diff --git a/output/noise.html b/output/noise.html
index a8d29b7..7738db3 100644
--- a/output/noise.html
+++ b/output/noise.html
@@ -5,17 +5,17 @@
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="pandoc" />
<meta name="author" content="Trevor Perrin (noise@trevp.net)" />
- <meta name="date" content="2017-04-07" />
- <title>Noise Protocol Framework: Core Specification</title>
+ <meta name="date" content="2017-05-09" />
+ <title>The Noise Protocol Framework: Book 1</title>
<style type="text/css">code{white-space: pre;}</style>
<link rel="stylesheet" href="spec_markdown.css" type="text/css" />
</head>
<body>
<div id="header">
-<h1 class="title">Noise Protocol Framework: Core Specification</h1>
+<h1 class="title">The Noise Protocol Framework: Book 1</h1>
<b>Author:</b> Trevor Perrin (noise@trevp.net)<br/>
<b>Revision:</b> 32draft<br/>
-<b>Date:</b> 2017-04-07<br/>
+<b>Date:</b> 2017-05-09<br/>
</div>
<div id="TOC">
<h2 class="toc">Table of Contents</h2>
@@ -53,7 +53,6 @@
<li><a href="#advanced-features">9. Advanced features</a><ul>
<li><a href="#dummy-static-public-keys">9.1. Dummy static public keys</a></li>
<li><a href="#channel-binding">9.2. Channel binding</a></li>
-<li><a href="#rekey">9.3. Rekey</a></li>
</ul></li>
<li><a href="#dh-functions-cipher-functions-and-hash-functions">10. DH functions, cipher functions, and hash functions</a><ul>
<li><a href="#the-25519-dh-functions">10.1. The <code>25519</code> DH functions</a></li>
@@ -80,6 +79,7 @@
</div>
<h1 id="introduction">1. Introduction</h1>
<p>Noise is a framework for crypto protocols based on Diffie-Hellman key agreement. Noise can describe protocols that consist of a single message as well as interactive protocols.</p>
+<p>This document is the first of two books which provide the specification for Noise. This document can be read as a self-contained specification, however Book 2 adds features that are important in many use cases.</p>
<h1 id="overview">2. Overview</h1>
<h2 id="terminology">2.1. Terminology</h2>
<p>A Noise protocol begins with two parties exchanging <strong>handshake messages</strong>. During this <strong>handshake phase</strong> the parties exchange DH public keys and perform a sequence of DH operations, hashing the DH results into a shared secret key. After the handshake phase each party can use this shared key to send encrypted <strong>transport messages</strong>.</p>
@@ -162,7 +162,6 @@
<ul>
<li><p><strong><code>ENCRYPT(k, n, ad, plaintext)</code></strong>: Encrypts <code>plaintext</code> using the cipher key <code>k</code> of 32 bytes and an 8-byte unsigned integer nonce <code>n</code> which must be unique for the key <code>k</code>. Returns the ciphertext. Encryption must be done with an &quot;AEAD&quot; encryption mode with the associated data <code>ad</code> (using the terminology from <span class="citation">[<a href="#ref-Rogaway:2002">1</a>]</span>) and returns a ciphertext that is the same size as the plaintext plus 16 bytes for authentication data. The entire ciphertext must be indistinguishable from random if the key is secret.</p></li>
<li><p><strong><code>DECRYPT(k, n, ad, ciphertext)</code></strong>: Decrypts <code>ciphertext</code> using a cipher key <code>k</code> of 32 bytes, an 8-byte unsigned integer nonce <code>n</code>, and associated data <code>ad</code>. Returns the plaintext, unless authentication fails, in which case an error is signaled to the caller.</p></li>
-<li><p><strong><code>REKEY(k)</code></strong>: Returns a new 32-byte cipher key as a pseudorandom function of <code>k</code>. If this function is not specifically defined for some set of cipher functions, then it defaults to returning the first 32 bytes from <code>ENCRYPT(k, maxnonce, zerolen, zeros)</code>, where <code>MAXNONCE</code> equals 2<sup>64</sup>-1, <code>zerolen</code> is a zero-length byte sequence, and <code>zeros</code> is a sequence of 32 bytes filled with zeros.</p></li>
</ul>
<h2 id="hash-functions">4.3. Hash functions</h2>
<p>Noise depends on the following <strong>hash function</strong> (and associated constants):</p>
@@ -173,8 +172,8 @@
</ul>
<p>Noise defines additional functions based on the above <code>HASH()</code> function:</p>
<ul>
-<li><p><strong><code>HMAC-HASH(key, data)</code></strong>: Applies <code>HMAC</code> from <span class="citation">[<a href="#ref-rfc2104">3</a>]</span> using the <code>HASH()</code> function. This function is only called as part of <code>HKDF()</code>, below.</p></li>
-<li><strong><code>HKDF(chaining_key, input_key_material)</code></strong>: Takes a <code>chaining_key</code> byte sequence of length <code>HASHLEN</code>, and an <code>input_key_material</code> byte sequence with length either zero bytes, 32 bytes, or <code>DHLEN</code> bytes. Returns a pair of byte sequences each of length <code>HASHLEN</code>, as follows:
+<li><p><strong><code>HMAC-HASH(key, data)</code></strong>: Applies <code>HMAC</code> from <span class="citation">[<a href="#ref-rfc2104">3</a>]</span> using the <code>HASH()</code> function. This function is only called as part of <code>HKDF2()</code>, below.</p></li>
+<li><strong><code>HKDF2(chaining_key, input_key_material)</code></strong>: Takes a <code>chaining_key</code> byte sequence of length <code>HASHLEN</code>, and an <code>input_key_material</code> byte sequence with length either zero bytes, 32 bytes, or <code>DHLEN</code> bytes. Returns a pair of byte sequences each of length <code>HASHLEN</code>, as follows:
<ul>
<li>Sets <code>temp_key = HMAC-HASH(chaining_key, input_key_material)</code>.</li>
<li>Sets <code>output1 = HMAC-HASH(temp_key, byte(0x01))</code>.</li>
@@ -182,7 +181,7 @@
<li>Returns (output1, output2).</li>
</ul></li>
</ul>
-<p>Note that <code>temp_key</code>, <code>output1</code>, and <code>output2</code> are all <code>HASHLEN</code> bytes in length. Also note that the <code>HKDF()</code> function is simply <code>HKDF</code> from <span class="citation">[<a href="#ref-rfc5869">4</a>]</span> with the <code>chaining_key</code> as HKDF <code>salt</code>, and zero-length HKDF <code>info</code>.</p>
+<p>Note that <code>temp_key</code>, <code>output1</code>, and <code>output2</code> are all <code>HASHLEN</code> bytes in length. Also note that the <code>HKDF2()</code> function is simply <code>HKDF</code> from <span class="citation">[<a href="#ref-rfc5869">4</a>]</span> with the <code>chaining_key</code> as HKDF <code>salt</code>, and zero-length HKDF <code>info</code>.</p>
<h1 id="processing-rules">5. Processing rules</h1>
<p>To precisely define the processing rules we adopt an object-oriented terminology, and present three &quot;objects&quot; which encapsulate state variables and provide &quot;methods&quot; which implement processing logic. These three objects are presented as a hierarchy: each higher-layer object includes one instance of the object beneath it. From lowest-layer to highest, the objects are:</p>
<ul>
@@ -200,11 +199,10 @@
<li><p><strong><code>k</code></strong>: A cipher key of 32 bytes (which may be <code>empty</code>). <code>Empty</code> is a special value which indicates <code>k</code> has not yet been initialized.</p></li>
<li><p><strong><code>n</code></strong>: An 8-byte (64-bit) unsigned integer nonce.</p></li>
</ul>
-<p>A <code>CipherState</code> responds to the following methods. The <code>++</code> post-increment operator applied to <code>n</code> means &quot;use the current <code>n</code> value, then increment it&quot;. The maximum <code>n</code> value (2<sup>64</sup>-1) is reserved for rekey (see <a href="#cipher-functions">Section 4.2</a> and <a href="#rekey">Section 9.3</a>) and must not be used. If incrementing <code>n</code> results in 2<sup>64</sup>-1, then any further <code>EncryptWithAd()</code> or <code>DecryptWithAd()</code> calls will signal an error to the caller.</p>
+<p>A <code>CipherState</code> responds to the following methods. The <code>++</code> post-increment operator applied to <code>n</code> means &quot;use the current <code>n</code> value, then increment it&quot;. The maximum <code>n</code> value (2<sup>64</sup>-1) is reserved for other use. If incrementing <code>n</code> results in 2<sup>64</sup>-1, then any further <code>EncryptWithAd()</code> or <code>DecryptWithAd()</code> calls will signal an error to the caller.</p>
<ul>
<li><p><strong><code>InitializeKey(key)</code></strong>: Sets <code>k = key</code>. Sets <code>n = 0</code>.</p></li>
<li><p><strong><code>HasKey()</code></strong>: Returns true if <code>k</code> is non-empty, false otherwise.</p></li>
-<li><p><strong><code>Rekey()</code></strong>: Sets <code>k = REKEY(k)</code>.</p></li>
<li><p><strong><code>EncryptWithAd(ad, plaintext)</code></strong>: If <code>k</code> is non-empty returns <code>ENCRYPT(k, n++, ad, plaintext)</code>. Otherwise returns <code>plaintext</code>.</p></li>
<li><p><strong><code>DecryptWithAd(ad, ciphertext)</code></strong>: If <code>k</code> is non-empty returns <code>DECRYPT(k, n++, ad, ciphertext)</code>. Otherwise returns <code>ciphertext</code>. If an authentication failure occurs in <code>DECRYPT()</code> then <code>n</code> is not incremented and an error is signaled to the caller.</p></li>
</ul>
@@ -224,7 +222,7 @@
</ul></li>
<li><p><strong><code>MixKey(input_key_material)</code></strong>: Executes the following steps:</p>
<ul>
-<li>Sets <code>ck, temp_k = HKDF(ck,input_key_material)</code>.</li>
+<li>Sets <code>ck, temp_k = HKDF2(ck,input_key_material)</code>.</li>
<li>If <code>HASHLEN</code> is 64, then truncates <code>temp_k</code> to 32 bytes.</li>
<li>Calls <code>InitializeKey(temp_k)</code>.</li>
</ul></li>
@@ -233,7 +231,7 @@
<li><p><strong><code>DecryptAndHash(ciphertext)</code></strong>: Sets <code>plaintext = DecryptWithAd(h, ciphertext)</code>, calls <code>MixHash(ciphertext)</code>, and returns <code>plaintext</code>. Note that if <code>k</code> is <code>empty</code>, the <code>DecryptWithAd()</code> call will set <code>plaintext</code> equal to <code>ciphertext</code>.</p></li>
<li><strong><code>Split()</code></strong>: Returns a pair of <code>CipherState</code> objects for encrypting transport messages. Executes the following steps, where <code>zerolen</code> is a zero-length byte sequence:
<ul>
-<li>Sets <code>temp_k1, temp_k2 = HKDF(ck, zerolen)</code>.</li>
+<li>Sets <code>temp_k1, temp_k2 = HKDF2(ck, zerolen)</code>.</li>
<li>If <code>HASHLEN</code> is 64, then truncates <code>temp_k1</code> and <code>temp_k2</code> to 32 bytes.</li>
<li>Creates two new <code>CipherState</code> objects <code>c1</code> and <code>c2</code>.</li>
<li>Calls <code>c1.InitializeKey(temp_k1)</code> and <code>c2.InitializeKey(temp_k2)</code>.</li>
@@ -266,9 +264,6 @@
<li><p>Calls <code>MixHash()</code> once for each public key listed in the pre-messages from <code>handshake_pattern</code>, with the specified public key as input (see <a href="#handshake-patterns">Section 8</a> for an explanation of pre-messages). If both initiator and responder have pre-messages, the initiator's public keys are hashed first.</p></li>
<li><p>Sets <code>message_patterns</code> to the message patterns from <code>handshake_pattern</code>.</p></li>
</ul></li>
-</ul>
-
-<ul>
<li><p><strong><code>WriteMessage(payload, message_buffer)</code></strong>: Takes a <code>payload</code> byte sequence which may be zero-length, and a <code>message_buffer</code> to write the output into. Performs the following steps:</p>
<ul>
<li><p>Fetches and deletes the next message pattern from <code>message_patterns</code>, then sequentially processes each token from the message pattern:</p>
@@ -753,15 +748,6 @@ Noise_XXfallback(e, s, rs):
<p>Parties might wish to execute a Noise protocol, then perform authentication at the application layer using signatures, passwords, or something else.</p>
<p>To support this, Noise libraries should expose the final value of h to the application as a <strong>handshake hash</strong> which uniquely identifies the Noise session.</p>
<p>Parties can then sign the handshake hash, or hash it along with their password, to get an authentication token which has a &quot;channel binding&quot; property: the token can't be used by the receiving party with a different sesssion.</p>
-<h2 id="rekey">9.3. Rekey</h2>
-<p>Parties might wish to periodically call the <code>Rekey()</code> function on their transport cipherstates, so that a compromise of cipherstate keys will not decrypt older messages. Periodic rekey might also be used to reduce the volume of data encrypted under a single cipher key (this is usually not important with good ciphers, though note the discussion on <code>AESGCM</code> data volumes in <a href="#security-considerations">Section 13</a> ).</p>
-<p>It is up to to the application if and when to perform rekey. For example:</p>
-<ul>
-<li><p>Applications might perform continuous rekey, where they rekey the relevant cipherstate after every transport message sent or received. This is simple and gives good protection to older ciphertexts, but might be difficult for implementations where changing keys is expensive.</p></li>
-<li><p>Applications might rekey a cipherstate automatically after it has has been used to send or receive some number of messages.</p></li>
-<li><p>Applications might choose to rekey based on arbitrary criteria, in which case they signal this to the other party by sending a message.</p></li>
-</ul>
-<p>Note that rekey doesn't reset the cipherstate's <code>n</code> value, so applications performing rekey must still perform a new handshake if sending 2<sup>64</sup> or more transport messages.</p>
<h1 id="dh-functions-cipher-functions-and-hash-functions">10. DH functions, cipher functions, and hash functions</h1>
<h2 id="the-25519-dh-functions">10.1. The <code>25519</code> DH functions</h2>
<ul>
@@ -809,7 +795,6 @@ Noise_XXfallback(e, s, rs):
<li><strong><code>HASHLEN</code></strong> = 64</li>
<li><strong><code>BLOCKLEN</code></strong> = 128</li>
</ul>
-
<h1 id="protocol-names">11. Protocol names</h1>
<p>To produce a <strong>Noise protocol name</strong> for <code>Initialize()</code> you concatenate the ASCII names for the handshake pattern, the DH functions, the cipher functions, and the hash function, with underscore separators. The resulting name must be 255 bytes or less. Examples:</p>
<ul>
@@ -833,12 +818,12 @@ Noise_XXfallback(e, s, rs):
<ul>
<li><p><strong>Session termination</strong>: Preventing attackers from truncating a stream of transport messages is an application responsibility. See previous section.</p></li>
<li><p><strong>Rollback</strong>: If parties decide on a Noise protocol based on some previous negotiation that is not included as prologue, then a rollback attack might be possible. This is a particular risk with fallback handshakes, and requires careful attention if a Noise handshake is preceded by communication between the parties.</p></li>
-<li><p><strong>Misusing public keys as secrets</strong>: It might be tempting to use a pattern with a pre-message public key and assume that a successful handshake implies the other party's knowledge of the public key. Unfortunately, this is not the case, since setting public keys to invalid values might cause predictable DH output. For example, a <code>Noise_NK_25519</code> initiator might send an invalid ephemeral public key to cause a known DH output of all zeros, despite not knowing the responder's static public key.</p></li>
+<li><p><strong>Misusing public keys as secrets</strong>: It might be tempting to use a pattern with a pre-message public key and assume that a successful handshake implies the other party's knowledge of the public key. Unfortunately, this is not the case, since setting public keys to invalid values might cause predictable DH output. For example, a <code>Noise_NK_25519</code> initiator might send an invalid ephemeral public key to cause a known DH output of all zeros, despite not knowing the responder's static public key. If the parties want to authenticate with a shared secret, it should be used as a &quot;PSK&quot; <span class="citation">[<a href="#ref-book2">11</a>]</span>.</p></li>
<li><p><strong>Channel binding</strong>: Depending on the DH functions, it might be possible for a malicious party to engage in multiple sessions that derive the same shared secret key by setting public keys to invalid values that cause predictable DH output (as in the previous bullet). It might also be possible to set public keys to equivalent values that cause the same DH output for different inputs. This is why a higher-level protocol should use the handshake hash (<code>h</code>) for a unique channel binding, instead of <code>ck</code>, as explained in <a href="#channel-binding">Section 9.2</a>.</p></li>
-<li><p><strong>Incrementing nonces</strong>: Reusing a nonce value for <code>n</code> with the same key <code>k</code> for encryption would be catastrophic. Implementations must carefully follow the rules for nonces. Nonces are not allowed to wrap back to zero due to integer overflow, and the maximum nonce value is reserved for rekeying. This means parties are not allowed to send more than 2<sup>64</sup>-1 transport messages.</p></li>
+<li><p><strong>Incrementing nonces</strong>: Reusing a nonce value for <code>n</code> with the same key <code>k</code> for encryption would be catastrophic. Implementations must carefully follow the rules for nonces. Nonces are not allowed to wrap back to zero due to integer overflow, and the maximum nonce value is reserved. This means parties are not allowed to send more than 2<sup>64</sup>-1 transport messages.</p></li>
<li><p><strong>Fresh ephemerals</strong>: Every party in a Noise protocol should send a new ephemeral public key and perform a DH with it prior to sending any encrypted data. Otherwise replay of a handshake message could trigger catastrophic key reuse. This is one rationale behind the patterns in <a href="#handshake-patterns">Section 7</a>, and the validity rules in <a href="#pattern-validity">Section 7.1</a>. It's also the reason why one-way handshakes only allow transport messages from the sender, not the recipient.</p></li>
<li><p><strong>Protocol names</strong>: The protocol name used with <code>Initialize()</code> must uniquely identify the combination of handshake pattern and crypto functions for every key it's used with (whether ephemeral key pair or static key pair). If the same secret key was reused with the same protocol name but a different set of cryptographic operations then bad interactions could occur.</p></li>
-<li><p><strong>Data volumes</strong>: The <code>AESGCM</code> cipher functions suffer a gradual reduction in security as the volume of data encrypted under a single key increases. Due to this, parties should not send more than 2<sup>56</sup> bytes (roughly 72 petabytes) encrypted by a single key. If sending such large volumes of data is a possibility then different cipher functions should be chosen, or the cipherstate should be rekeyed (<a href="#rekey">Section 9.3</a>) before this limit is reached.</p></li>
+<li><p><strong>Data volumes</strong>: The <code>AESGCM</code> cipher functions suffer a gradual reduction in security as the volume of data encrypted under a single key increases. Due to this, parties should not send more than 2<sup>56</sup> bytes (roughly 72 petabytes) encrypted by a single key. If sending such large volumes of data is a possibility then different cipher functions should be chosen.</p></li>
<li><p><strong>Hash collisions</strong>: If an attacker can find hash collisions on prologue data or the handshake hash, they may be able to perform &quot;transcript collision&quot; attacks that trick the parties into having different views of handshake data. It is important to use Noise with collision-resistant hash functions, and replace the hash function at any sign of weakness.</p></li>
<li><p><strong>Implementation fingerprinting</strong>: If this protocol is used in settings with anonymous parties, care should be taken that implementations behave identically in all cases. This may require mandating exact behavior for handling of invalid DH public keys.</p></li>
</ul>
@@ -873,16 +858,6 @@ Noise_XXfallback(e, s, rs):
<li><p>AES-GCM uses a big-endian block counter internally.</p></li>
<li><p>It makes sense to use consistent endianness in the cipher code.</p></li>
</ul>
-<p>Rekey defaults to using encryption with the nonce 2<sup>64</sup>-1 because:</p>
-<ul>
-<li>With <code>AESGCM</code> and <code>ChaChaPoly</code> rekey can be computed efficiently (the &quot;encryption&quot; just needs to apply the cipher, and can skip calculation of the authentication tag).</li>
-</ul>
-<p>Rekey doesn't reset the nonce <code>n</code> to zero because:</p>
-<ul>
-<li><p>Leaving <code>n</code> unchanged is simple.</p></li>
-<li><p>If the cipher has a weakness such that repeated rekeying gives rise to a cycle of keys, then letting <code>n</code> advance will avoid catastrophic reuse of the same <code>k</code> and <code>n</code> values.</p></li>
-<li><p>Letting <code>n</code> advance puts a bound on the total number of encryptions that can be performed with a set of derived keys.</p></li>
-</ul>
<h2 id="hash-functions-and-hashing">14.2. Hash functions and hashing</h2>
<p>The recommended hash function families are SHA2 and BLAKE2 because:</p>
<ul>
@@ -898,12 +873,12 @@ Noise_XXfallback(e, s, rs):
<p>The <code>MixKey()</code> design uses HKDF because:</p>
<ul>
<li><p>HKDF is well-known and HKDF &quot;chains&quot; are used in similar ways in other protocols (e.g. Signal, IPsec, TLS 1.3).</p></li>
-<li><p>HKDF has a published analysis <span class="citation">[<a href="#ref-hkdfpaper">11</a>]</span>.</p></li>
+<li><p>HKDF has a published analysis <span class="citation">[<a href="#ref-hkdfpaper">12</a>]</span>.</p></li>
<li><p>HKDF applies multiple layers of hashing between each <code>MixKey()</code> input. This &quot;extra&quot; hashing might mitigate the impact of hash function weakness.</p></li>
</ul>
<p>HMAC is used with all hash functions instead of allowing hashes to use a more specialized function (e.g. keyed BLAKE2), because:</p>
<ul>
-<li><p>HKDF requires the use of HMAC, and some of the HKDF analysis in <span class="citation">[<a href="#ref-hkdfpaper">11</a>]</span> depends on the nested structure of HMAC.</p></li>
+<li><p>HKDF requires the use of HMAC, and some of the HKDF analysis in <span class="citation">[<a href="#ref-hkdfpaper">12</a>]</span> depends on the nested structure of HMAC.</p></li>
<li><p>HMAC is widely used with Merkle-Damgard hashes such as SHA2. SHA3 candidates such as Keccak and BLAKE were required to be suitable with HMAC. Thus, HMAC should be applicable to all widely-used hash functions.</p></li>
<li><p>HMAC applies nested hashing to process each input. This &quot;extra&quot; hashing might mitigate the impact of hash function weakness.</p></li>
<li><p>HMAC (and HKDF) are widely-used constructions. If some weakness is found in a hash function, cryptanalysts will likely analyze that weakness in the context of HMAC and HKDF.</p></li>
@@ -941,17 +916,17 @@ Noise_XXfallback(e, s, rs):
<li><p>Explicit nonces make it easier to &quot;backdoor&quot; crypto implementations, e.g. by modifying the RNG so that key recovery data is leaked through the nonce fields.</p></li>
</ul>
<h1 id="ipr">15. IPR</h1>
-<p>The Noise specification (this document) is hereby placed in the public domain.</p>
+<p>The Noise specification Book 1 (this document) is hereby placed in the public domain.</p>
<h1 id="acknowledgements">16. Acknowledgements</h1>
<p>Noise is inspired by:</p>
<ul>
-<li>The NaCl and CurveCP protocols from Dan Bernstein et al <span class="citation">[<a href="#ref-nacl">12</a>], [<a href="#ref-curvecp">13</a>]</span>.</li>
-<li>The SIGMA and HOMQV protocols from Hugo Krawczyk <span class="citation">[<a href="#ref-sigma">14</a>], [<a href="#ref-homqv">15</a>]</span>.</li>
-<li>The Ntor protocol from Ian Goldberg et al <span class="citation">[<a href="#ref-ntor">16</a>]</span>.</li>
-<li>The analysis of OTR by Mario Di Raimondo et al <span class="citation">[<a href="#ref-otr">17</a>]</span>.</li>
-<li>The analysis by Caroline Kudla and Kenny Paterson of &quot;Protocol 4&quot; by Simon Blake-Wilson et al <span class="citation">[<a href="#ref-kudla2005">18</a>], [<a href="#ref-blakewilson1997">19</a>]</span>.</li>
-<li>Mike Hamburg's proposals for a sponge-based protocol framework, which led to STROBE <span class="citation">[<a href="#ref-moderncryptostrobe">20</a>], [<a href="#ref-strobe">21</a>]</span>.</li>
-<li>The KDF chains used in the Double Ratchet Algorithm <span class="citation">[<a href="#ref-doubleratchet">22</a>]</span>.</li>
+<li>The NaCl and CurveCP protocols from Dan Bernstein et al <span class="citation">[<a href="#ref-nacl">13</a>], [<a href="#ref-curvecp">14</a>]</span>.</li>
+<li>The SIGMA and HOMQV protocols from Hugo Krawczyk <span class="citation">[<a href="#ref-sigma">15</a>], [<a href="#ref-homqv">16</a>]</span>.</li>
+<li>The Ntor protocol from Ian Goldberg et al <span class="citation">[<a href="#ref-ntor">17</a>]</span>.</li>
+<li>The analysis of OTR by Mario Di Raimondo et al <span class="citation">[<a href="#ref-otr">18</a>]</span>.</li>
+<li>The analysis by Caroline Kudla and Kenny Paterson of &quot;Protocol 4&quot; by Simon Blake-Wilson et al <span class="citation">[<a href="#ref-kudla2005">19</a>], [<a href="#ref-blakewilson1997">20</a>]</span>.</li>
+<li>Mike Hamburg's proposals for a sponge-based protocol framework, which led to STROBE <span class="citation">[<a href="#ref-moderncryptostrobe">21</a>], [<a href="#ref-strobe">22</a>]</span>.</li>
+<li>The KDF chains used in the Double Ratchet Algorithm <span class="citation">[<a href="#ref-doubleratchet">23</a>]</span>.</li>
</ul>
<p>General feedback on the spec and design came from: Moxie Marlinspike, Jason Donenfeld, Rhys Weatherley, Tiffany Bennett, Jonathan Rudenberg, Stephen Touset, Tony Arcieri, Alex Wied, Alexey Ermishkin, and Olaoluwa Osuntokun.</p>
<p>Thanks to Tom Ritter, Karthikeyan Bhargavan, David Wong, Klaus Hartke, Dan Burkert, Jake McGinty, and Yin Guanhao for editorial feedback.</p>
@@ -990,41 +965,44 @@ Noise_XXfallback(e, s, rs):
<div id="ref-rfc7693">
<p>[10] M.-J. Saarinen and J.-P. Aumasson, “The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC).” Internet Engineering Task Force; RFC 7693 (Informational); IETF, Nov-2015. <a href="http://www.ietf.org/rfc/rfc7693.txt" class="uri">http://www.ietf.org/rfc/rfc7693.txt</a></p>
</div>
+<div id="ref-book2">
+<p>[11] Trevor Perrin, “The Noise Protocol Framework: Book 2.” 2017. <a href="https://noiseprotocol.org/noise_book2.pdf" class="uri">https://noiseprotocol.org/noise_book2.pdf</a></p>
+</div>
<div id="ref-hkdfpaper">
-<p>[11] H. Krawczyk, “‘Cryptographic extraction and key derivation: The hkdf scheme’.” Cryptology ePrint Archive, Report 2010/264, 2010. <a href="http://eprint.iacr.org/2010/264" class="uri">http://eprint.iacr.org/2010/264</a></p>
+<p>[12] H. Krawczyk, “‘Cryptographic extraction and key derivation: The hkdf scheme’.” Cryptology ePrint Archive, Report 2010/264, 2010. <a href="http://eprint.iacr.org/2010/264" class="uri">http://eprint.iacr.org/2010/264</a></p>
</div>
<div id="ref-nacl">
-<p>[12] D. J. Bernstein, T. Lange, and P. Schwabe, “NaCl: Networking and Cryptography Library.”. <a href="https://nacl.cr.yp.to/" class="uri">https://nacl.cr.yp.to/</a></p>
+<p>[13] D. J. Bernstein, T. Lange, and P. Schwabe, “NaCl: Networking and Cryptography Library.”. <a href="https://nacl.cr.yp.to/" class="uri">https://nacl.cr.yp.to/</a></p>
</div>
<div id="ref-curvecp">
-<p>[13] D. J. Bernstein, “CurveCP: Usable security for the Internet.”. <a href="https://curvecp.org" class="uri">https://curvecp.org</a></p>
+<p>[14] D. J. Bernstein, “CurveCP: Usable security for the Internet.”. <a href="https://curvecp.org" class="uri">https://curvecp.org</a></p>
</div>
<div id="ref-sigma">
-<p>[14] H. Krawczyk, “SIGMA: The ‘SIGn-and-MAc’ Approach to Authenticated Diffie-Hellman and Its Use in the IKE Protocols,” in Advances in Cryptology - CRYPTO 2003, 2003. <a href="http://webee.technion.ac.il/~hugo/sigma.html" class="uri">http://webee.technion.ac.il/~hugo/sigma.html</a></p>
+<p>[15] H. Krawczyk, “SIGMA: The ‘SIGn-and-MAc’ Approach to Authenticated Diffie-Hellman and Its Use in the IKE Protocols,” in Advances in Cryptology - CRYPTO 2003, 2003. <a href="http://webee.technion.ac.il/~hugo/sigma.html" class="uri">http://webee.technion.ac.il/~hugo/sigma.html</a></p>
</div>
<div id="ref-homqv">
-<p>[15] S. Halevi and H. Krawczyk, “One-Pass HMQV and Asymmetric Key-Wrapping.” Cryptology ePrint Archive, Report 2010/638, 2010. <a href="http://eprint.iacr.org/2010/638" class="uri">http://eprint.iacr.org/2010/638</a></p>
+<p>[16] S. Halevi and H. Krawczyk, “One-Pass HMQV and Asymmetric Key-Wrapping.” Cryptology ePrint Archive, Report 2010/638, 2010. <a href="http://eprint.iacr.org/2010/638" class="uri">http://eprint.iacr.org/2010/638</a></p>
</div>
<div id="ref-ntor">
-<p>[16] I. Goldberg, D. Stebila, and B. Ustaoglu, “Anonymity and One-way Authentication in Key Exchange Protocols,” Design, Codes, and Cryptography, vol. 67, no. 2, May 2013. <a href="http://cacr.uwaterloo.ca/techreports/2011/cacr2011-11.pdf" class="uri">http://cacr.uwaterloo.ca/techreports/2011/cacr2011-11.pdf</a></p>
+<p>[17] I. Goldberg, D. Stebila, and B. Ustaoglu, “Anonymity and One-way Authentication in Key Exchange Protocols,” Design, Codes, and Cryptography, vol. 67, no. 2, May 2013. <a href="http://cacr.uwaterloo.ca/techreports/2011/cacr2011-11.pdf" class="uri">http://cacr.uwaterloo.ca/techreports/2011/cacr2011-11.pdf</a></p>
</div>
<div id="ref-otr">
-<p>[17] M. Di Raimondo, R. Gennaro, and H. Krawczyk, “Secure Off-the-record Messaging,” in Proceedings of the 2005 ACM Workshop on Privacy in the Electronic Society, 2005. <a href="http://www.dmi.unict.it/diraimondo/web/wp-content/uploads/papers/otr.pdf" class="uri">http://www.dmi.unict.it/diraimondo/web/wp-content/uploads/papers/otr.pdf</a></p>
+<p>[18] M. Di Raimondo, R. Gennaro, and H. Krawczyk, “Secure Off-the-record Messaging,” in Proceedings of the 2005 ACM Workshop on Privacy in the Electronic Society, 2005. <a href="http://www.dmi.unict.it/diraimondo/web/wp-content/uploads/papers/otr.pdf" class="uri">http://www.dmi.unict.it/diraimondo/web/wp-content/uploads/papers/otr.pdf</a></p>
</div>
<div id="ref-kudla2005">
-<p>[18] C. Kudla and K. G. Paterson, “Modular Security Proofs for Key Agreement Protocols,” in Advances in Cryptology - ASIACRYPT 2005: 11th International Conference on the Theory and Application of Cryptology and Information Security, 2005. <a href="http://www.isg.rhul.ac.uk/~kp/ModularProofs.pdf" class="uri">http://www.isg.rhul.ac.uk/~kp/ModularProofs.pdf</a></p>
+<p>[19] C. Kudla and K. G. Paterson, “Modular Security Proofs for Key Agreement Protocols,” in Advances in Cryptology - ASIACRYPT 2005: 11th International Conference on the Theory and Application of Cryptology and Information Security, 2005. <a href="http://www.isg.rhul.ac.uk/~kp/ModularProofs.pdf" class="uri">http://www.isg.rhul.ac.uk/~kp/ModularProofs.pdf</a></p>
</div>
<div id="ref-blakewilson1997">
-<p>[19] S. Blake-Wilson, D. Johnson, and A. Menezes, “Key agreement protocols and their security analysis,” in Crytography and Coding: 6th IMA International Conference Cirencester, UK, December 17–19, 1997 Proceedings, 1997. <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.387" class="uri">http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.387</a></p>
+<p>[20] S. Blake-Wilson, D. Johnson, and A. Menezes, “Key agreement protocols and their security analysis,” in Crytography and Coding: 6th IMA International Conference Cirencester, UK, December 17–19, 1997 Proceedings, 1997. <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.387" class="uri">http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.387</a></p>
</div>
<div id="ref-moderncryptostrobe">
-<p>[20] M. Hamburg, “Key Exchange and DuplexWrap-like protocols.” Noise@moderncrypto.org Mailing List, 2015. <a href="https://moderncrypto.org/mail-archive/noise/2015/000098.html" class="uri">https://moderncrypto.org/mail-archive/noise/2015/000098.html</a></p>
+<p>[21] M. Hamburg, “Key Exchange and DuplexWrap-like protocols.” Noise@moderncrypto.org Mailing List, 2015. <a href="https://moderncrypto.org/mail-archive/noise/2015/000098.html" class="uri">https://moderncrypto.org/mail-archive/noise/2015/000098.html</a></p>
</div>
<div id="ref-strobe">
-<p>[21] Mike Hamburg, “The STROBE protocol framework.” Cryptology ePrint Archive, Report 2017/003, 2017. <a href="http://eprint.iacr.org/2017/003" class="uri">http://eprint.iacr.org/2017/003</a></p>
+<p>[22] Mike Hamburg, “The STROBE protocol framework.” Cryptology ePrint Archive, Report 2017/003, 2017. <a href="http://eprint.iacr.org/2017/003" class="uri">http://eprint.iacr.org/2017/003</a></p>
</div>
<div id="ref-doubleratchet">
-<p>[22] T. Perrin and M. Marlinspike, “The Double Ratchet Algorithm,” 2016. <a href="https://whispersystems.org/docs/specifications/doubleratchet/" class="uri">https://whispersystems.org/docs/specifications/doubleratchet/</a></p>
+<p>[23] T. Perrin and M. Marlinspike, “The Double Ratchet Algorithm,” 2016. <a href="https://whispersystems.org/docs/specifications/doubleratchet/" class="uri">https://whispersystems.org/docs/specifications/doubleratchet/</a></p>
</div>
</div>
</body>
diff --git a/output/noise.pdf b/output/noise.pdf
index 65ef5f8..a195025 100644
--- a/output/noise.pdf
+++ b/output/noise.pdf
Binary files differ
diff --git a/output/noise_book2.pdf b/output/noise_book2.pdf
new file mode 100644
index 0000000..82a1b58
--- /dev/null
+++ b/output/noise_book2.pdf
Binary files differ