Network Working Group D. Miller Internet-Draft OpenSSH Intended status: Standards Track S.G. Tatham Expires: 18 September 2025 PuTTY S. Josefsson Independent 17 March 2025 Secure Shell (SSH) authenticated encryption cipher: chacha20-poly1305 draft-ietf-sshm-chacha20-poly1305-01 Abstract This document describes the Secure Shell (SSH) chacha20-poly1305 authenticated encryption cipher. Note This document is UNFINISHED. Before publication as an RFC, it must no longer contain any instance of the string "FIXME", which is used to mark where required information has not yet been added. Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 18 September 2025. Copyright Notice Copyright (c) 2025 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Miller, et al. Expires 18 September 2025 [Page 1] Internet-Draft SSH chacha20-poly1305 March 2025 Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 2. ChaCha20 . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3. Poly1305 . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4. Negotiation . . . . . . . . . . . . . . . . . . . . . . . . . 5 5. Detailed Construction . . . . . . . . . . . . . . . . . . . . 5 6. Packet Handling . . . . . . . . . . . . . . . . . . . . . . . 6 7. Rekeying . . . . . . . . . . . . . . . . . . . . . . . . . . 6 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 7 9. Security Considerations . . . . . . . . . . . . . . . . . . . 7 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 8 11.1. Normative References . . . . . . . . . . . . . . . . . . 8 11.2. Informative References . . . . . . . . . . . . . . . . . 8 Appendix A. Worked Example . . . . . . . . . . . . . . . . . . . 9 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 14 1. Introduction ChaCha20 is a stream cipher designed by Daniel Bernstein and described in [ChaCha], with some details inherited from [Salsa20]. It operates by permuting 128 fixed bits, 128 or 256 bits of key, a 64 bit nonce and a 64 bit counter into 64 bytes of output. This output is used as a keystream, with any unused bytes simply discarded. Poly1305 [Poly1305], also by Daniel Bernstein, is a one-time Carter- Wegman MAC that computes a 128 bit integrity tag given a message and a single-use 256 bit secret key. The "chacha20-poly1305" cipher combines these two primitives into an authenticated encryption mode. The construction used is based on that proposed for TLS by Adam Langley in [I-D.agl-tls-chacha20poly1305], but differs in the layout of data passed to the MAC and in the addition of encryption of the packet lengths. In particular, the key generation for Poly1305 is based on ChaCha20, instead of AES as described in [Poly1305]. This document specifies and registers "chacha20-poly1305" to be identical to the already widely deployed "chacha20-poly1305@openssh.com". Miller, et al. Expires 18 September 2025 [Page 2] Internet-Draft SSH chacha20-poly1305 March 2025 2. ChaCha20 ChaCha20 is defined by two long documents, but the actual cipher definition is simple enough to restate the full specification here. ChaCha20 operates on an array of sixteen 32-bit integers, usually written in the form of a square matrix, with x[0], ..., x[3] on the top row, ..., x[12], ..., x[15] on the bottom row. The ChaCha20 permutation is a fixed, keyless transformation which turns an input matrix into an output one. It is described in full by the following pseudocode, in which addition is modulo 2^32, and ROL describes bitwise left rotation of 32-bit integers: one_16th_of_a_round(matrix, p, q, r, rotation): matrix[p] <- matrix[p] + matrix[q] matrix[r] <- (matrix[r] XOR matrix[p]) ROL rotation one_quarter_of_a_round(matrix, a, b, c, d): one_16th_of_a_round(matrix, a, b, d, 16) one_16th_of_a_round(matrix, c, d, b, 12) one_16th_of_a_round(matrix, a, b, d, 8) one_16th_of_a_round(matrix, c, d, b, 7) even_numbered_round(matrix): one_quarter_of_a_round(matrix, 0, 4, 8, 12) one_quarter_of_a_round(matrix, 1, 5, 9, 13) one_quarter_of_a_round(matrix, 2, 6, 10, 14) one_quarter_of_a_round(matrix, 3, 7, 11, 15) odd_numbered_round(matrix): one_quarter_of_a_round(matrix, 0, 5, 10, 15) one_quarter_of_a_round(matrix, 1, 6, 11, 12) one_quarter_of_a_round(matrix, 2, 7, 8, 13) one_quarter_of_a_round(matrix, 3, 4, 9, 14) chacha20(matrix): orig <- copy(matrix) repeat 10 times: even_numbered_round(matrix) odd_numbered_round(matrix) matrix = matrix + orig // element-wise addition of two matrices Figure 1: Pseudocode of the ChaCha20 transform To generate a ChaCha20 cipher block, the first four words x[0],...,x[3] of the input matrix are initialized to fixed values obtained by encoding the string "expand 32-byte k" in ASCII and Miller, et al. Expires 18 September 2025 [Page 3] Internet-Draft SSH chacha20-poly1305 March 2025 interpreting those 16 bytes as the little-endian encoding of four 32-bit integers. The next 8 words x[4],...,x[11] are initialized from the 32-byte cipher key in the same fashion. The next 2 words x[12],x[13] are a 64-bit counter which is incremented for each output data block, with x[12] being the low-order 32 bits of the counter and x[13] the high-order bits. The final 2 words x[14],x[15] are initialized from an 8-byte "nonce" which must be a unique identifier for each separate message encrypted with the same key. To create a full ChaCha20 cipher stream, a succession of input matrices is constructed as above, incrementing the 64-bit block counter by 1 in each matrix. Each input matrix is independently transformed via the permutation described above, and the output matrix is converted into 64 bytes of cipher stream by encoding each 32-bit integer little-endian. Generate as many blocks of the cipher stream as necessary; XOR the cipher stream byte-wise into the message to be encrypted; discard any remaining part of the final block. 3. Poly1305 The Poly1305 authenticator used in this specification differs from the description in [Poly1305] in how it generates the key material, so it is convenient to specify that in full here as well. Poly1305 as described here requires two 16-byte key inputs. Each one is interpreted as the little-endian encoding of a 128-bit integer. One of these integers is then bitwise-ANDed with the integer 0x0FFFFFFC0FFFFFFC0FFFFFFC0FFFFFFF, and the result is denoted as 'r'. The other integer is denoted as 'n', and requires no modification. The input message to be authenticated is divided into blocks of 16 bytes, with a short block at the end if its length is not a multiple of 16. Each block is converted into an integer of size up to 2^129, by appending the byte 0x01 and then interpreting the extended block as the little-endian encoding of an integer. (So all the resulting integers have bit 128 set, except that if there is a final short block of s < 16 bytes, then that integer will have bit (8*s) set.) Denote the message integers as C[1], C[2], ..., C[m]. Then the MAC is computed as follows. Perform a polynomial evaluation in which the variable is the key integer 'r'; the constant coefficient is zero; the coefficient of r^1 is c[m], the coefficient of r^2 is c[m-1], ..., and the coefficient of r^m is c[1]. This can be achieved by initializing an accumulator A to zero, and then for each coefficient c[i], in turn, setting A <- (A + c[i]) * r. Miller, et al. Expires 18 September 2025 [Page 4] Internet-Draft SSH chacha20-poly1305 March 2025 The result of this evaluation is reduced modulo 2^130-5 to give the least non-negative residue. (It follows that the intermediate results of the polynomial evaluation can be reduced in the same way, without affecting the output.) That residue is then reduced again modulo 2^128, and added modulo 2^128 to the other key integer 'n'. This final 128-bit integer is encoded little-endian and forms the output authentication tag. In the original specification [Poly1305], the key provided by the application consists of 16 bytes of data used to create 'r' as described above, and another 16 bytes used as an AES key to encrypt a per-message nonce, with the ciphertext being used to create 'n'. So 'r' is reused between messages, with only 'n' changing. However, in this specification, both 'r' and 'n' are created from parts of the output of the same ChaCha20 transformation, as described below. So both values change in every message. 4. Negotiation The "chacha20-poly1305" offers both encryption and authentication. As such, no separate MAC is required. If the "chacha20-poly1305" cipher is selected in key exchange, the offered MAC algorithms are ignored and no MAC is required to be negotiated. 5. Detailed Construction The "chacha20-poly1305" cipher requires 512 bits of key material as output from the SSH key exchange. This forms two 256 bit keys (K_1 and K_2), used by two separate instances of chacha20. The instance keyed by the second half of the key material, K_2, is a stream cipher that is used only to encrypt the 4 byte packet length field. The instance keyed by the first half K_1 is used to encrypt the remainder of the packet. The concatenated ciphertext from both of these operations is then authenticated using Poly1305 with a key derived from the K_1 cipher stream. The 8-byte nonce required by ChaCha20 is obtained by encoding the SSH packet sequence number as a 64-bit integer, in the usual SSH big- endian encoding. Since the SSH packet sequence number is defined to be a 32-bit integer, this means that the first four bytes of the ChaCha20 nonce, creating the input matrix entry x[14], are always zero. The second four bytes are the big-endian encoding of the SSH sequence number, which means that the matrix entry x[15] is the sequence number with its byte order reversed, because that results from decoding the same four bytes little-endian. Miller, et al. Expires 18 September 2025 [Page 5] Internet-Draft SSH chacha20-poly1305 March 2025 For the K_2 cipher instance that encrypts the length, the block counter is always 0, because only one block is needed (and only the first four bytes of that block are used). For the K_1 cipher instance used for the packet payload, the block counter value starts at 1 and increments to generate the cipher stream that encrypts the packet. To generate keying information for the Poly1305 MAC, the K_1 cipher instance is run with the same key and nonce but a block counter value of 0. The first 16 bytes of the output are converted into the Poly1305 key integer 'r' at which the polynomial is evaluated, by decoding them as a 128-bit little-endian integer and clearing certain bits of that integer as described in [Poly1305]. The second 16 bytes are converted into the mask integer 'n' added at the end of the Poly1305 algorithm. 6. Packet Handling When receiving a packet, the length must be decrypted first. When 4 bytes of ciphertext length have been received, they may be decrypted using the K_2 key, a nonce consisting of the packet sequence number encoded as a uint64 under the usual SSH wire encoding and a zero block counter to obtain the plaintext length. Once the entire packet has been received, the MAC MUST be checked before decryption. A per-packet Poly1305 key is generated as described above and the MAC tag calculated using Poly1305 with this key over the ciphertext of the packet length and the payload together. The calculated MAC is then compared in constant time with the one appended to the packet and the packet decrypted using ChaCha20 as described above (with K_1, the packet sequence number as nonce and a starting block counter of 1). To send a packet, first encode the 4 byte length and encrypt it using K_2. Encrypt the packet payload (using K_1) and append it to the encrypted length. Finally, calculate a MAC tag and append it. 7. Rekeying ChaCha20 must never reuse a {key, nonce} for encryption nor may it be used to encrypt more than 2^70 bytes under the same {key, nonce}. The SSH Transport protocol [RFC4253] recommends a far more conservative rekeying every 1GB of data sent or received. If this recommendation is followed, then "chacha20-poly1305" requires no special handling in this area. Miller, et al. Expires 18 September 2025 [Page 6] Internet-Draft SSH chacha20-poly1305 March 2025 8. Acknowledgements Markus Friedl helped on the design. Theo de Raadt supported to register the OpenSSH private-use cipher for generic use. 9. Security Considerations The use of this cipher and MAC combination has a KNOWN SECURITY VULNERABILITY. This specification modifies the SSH binary packet protocol in a way that makes the encryption and authentication of every packet independent: instead of generating a single continuous cipher stream and dividing it at packet boundaries, a fresh cipher stream is started for each packet based on that packet's sequence number. This makes it possible for a MITM attacker to delete an entire packet from one direction of the SSH data stream, if they can manipulate the receiving end's idea of the packet sequence number. In the "Terrapin" attack [Terrapin] (CVE-2023-48795), this is achieved by combining deletion of the first encrypted packet with injection of an earlier SSH_MSG_IGNORE packet, in the cleartext segment of the SSH session before the initial key exchange completes. The injected and deleted packets have opposite effects on the sequence number and cancel one another out, so that the receiving side uses the correct sequence number to decrypt the first remaining packet in the cipher stream, and never detects the modification. This is a breach of the SSH transport protocol's security guarantee. Implementations deploying the "chacha20-poly1305" cipher and MAC combination MUST support a means of mitigating this attack, and deploy the mitigation if the other end of the SSH connection is also capable of doing so. As of 2025, a mitigation commonly deployed is called Strict KEX [I-D.miller-sshm-strict-kex]. In this modification, the packet sequence number used for cryptographic purposes is reset to 0 immediately after each SSH_MSG_NEWKEYS, and extraneous packets such as SSH_MSG_IGNORE are prohibited in the initial cleartext segment of the session. On the other hand, the use of two separate cipher instances is itself a mitigation for another family of attacks found in SSH (e.g. CVE- 2008-5161), in which an attacker uses the fact that the receiver acts on the decrypted length before checking the MAC, to obtain an oracle for the packet payload cipher by modifying the packet length field and observing the receiver's response. In this protocol, the length is encrypted using an independently-keyed cipher, so any attempt to exploit the decryption of the length field only gains information about the length cipher, and not about the separate cipher instance that encrypts the packet payload. Miller, et al. Expires 18 September 2025 [Page 7] Internet-Draft SSH chacha20-poly1305 March 2025 In the original specification for Poly1305, the nonce value added to the result of the polynomial evaluation was generated by AES. In this specification, ChaCha20 is used instead because [FIXME: presumably "it seemed silly to use two ciphers"]. This is believed not to negatively impact security because [FIXME: presumably something to do with the security proof in Poly1305]. 10. IANA Considerations IANA is requested to add a new "Encryption Algorithm Name" of "chacha20-poly1305" the "Encryption Algorithm Names" registry for Secure Shell (SSH) Protocol Parameters [IANA-ENCALG] with a "Reference" field referring this RFC and the "OK to implement" field of "MUST". 11. References 11.1. Normative References [RFC4253] Ylonen, T. and C. Lonvick, Ed., "The Secure Shell (SSH) Transport Layer Protocol", RFC 4253, DOI 10.17487/RFC4253, January 2006, . [I-D.miller-sshm-strict-kex] Miller, D., "SSH Agent Protocol", Work in Progress, Internet-Draft, draft-miller-sshm-strict-kex-00, 17 March 2025, . [IANA-ENCALG] IANA, "Secure Shell (SSH) Protocol Parameters: Encryption Algorithm Names", . 11.2. Informative References [I-D.agl-tls-chacha20poly1305] Langley, A. and W. Chang, "ChaCha20 and Poly1305 based Cipher Suites for TLS", Work in Progress, Internet-Draft, draft-agl-tls-chacha20poly1305-04, 22 November 2013, . [ChaCha] Bernstein, J., "ChaCha, a variant of Salsa20", January 2008, . Miller, et al. Expires 18 September 2025 [Page 8] Internet-Draft SSH chacha20-poly1305 March 2025 [Salsa20] Bernstein, J., "The Salsa20 family of stream ciphers", December 2007, . [Poly1305] Bernstein, J., "The Poly1305-AES message-authentication code", March 2005, . [Terrapin] Bäumer, F., Brinkmann, M., and J. Schwenk, "Terrapin Attack: Breaking SSH Channel Integrity By Sequence Number Manipulation", December 2023, . Appendix A. Worked Example Since this specification modifies both Poly1305 (by generating its key data using a different cipher) and the SSH binary packet protocol, it is useful to present a full example of how an SSH packet is encrypted and authenticated to generate the exact data sent over the network. The example input packet, described using the conventional SSH marshalling notation, is as follows: byte 0x5e (SSH2_MSG_CHANNEL_DATA) uint32 0 (recipient channel id) string "Lorem ipsum dolor sit amet, consectetur adipisicing elit" Figure 2: Logical form of the input packet After encoding in the binary packet protocol, this becomes the following data: uint32 0x48 (packet length not including this field) byte 0x06 (number of bytes of padding) byte 0x5e (SSH2_MSG_CHANNEL_DATA) uint32 0 (recipient channel id) string "Lorem ipsum dolor sit amet, consectetur adipisicing elit" byte[6] 0x4e 0x43 0xe8 0x04 0xdc 0x6c (random padding bytes) Figure 3: Full encoding of the input packet before encryption which in turn is encoded into the following bytes: Miller, et al. Expires 18 September 2025 [Page 9] Internet-Draft SSH chacha20-poly1305 March 2025 00 00 00 48 06 5e 00 00 00 00 00 00 00 38 4c 6f 72 65 6d 20 69 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 20 61 64 69 70 69 73 69 63 69 6e 67 20 65 6c 69 74 4e 43 e8 04 dc 6c Figure 4: Input packet encoded as hex bytes, before encryption In this example connection, this packet was sent from client to server, with a sequence number of 7. The encryption key for the client-to-server direction of the connection, derived as specified in RFC4253 section 7.2, is 64 bytes long and consists of the following bytes: 8b bf f6 85 5f c1 02 33 8c 37 3e 73 aa c0 c9 14 f0 76 a9 05 b2 44 4a 32 ee ca ff ea e2 2b ec c5 e9 b7 a7 a5 82 5a 82 49 34 6e c1 c2 83 01 cf 39 45 43 fc 75 69 88 7d 76 e1 68 f3 75 62 ac 07 40 Figure 5: Key material output from the key exchange To encrypt the first 4 bytes of the packet, consisting of the length, the following matrix of 32-bit integers is constructed as input to the ChaCha20 permutation, with the key material derived from the second half of the above block, and a block counter value of 0. (Note that the packet sequence number, in the bottom right corner, has been endianness-swapped as a result of encoding it big-endian in the SSH convention and then decoding it little-endian in the ChaCha20 convention.) 0x61707865 0x3320646e 0x79622d32 0x6b206574 0xa5a7b7e9 0x49825a82 0xc2c16e34 0x39cf0183 0x75fc4345 0x767d8869 0x75f368e1 0x4007ac62 0x00000000 0x00000000 0x00000000 0x07000000 Figure 6: ChaCha20 preimage matrix for encrypting the packet length After the ChaCha20 transformation, the output matrix is as follows: 0xaccc3e2c 0xf62f4341 0x94f7b07b 0xe6f481fb 0x75306ddf 0x8b82a326 0x5b1aec13 0x119ff043 0x0ae8ba12 0x1cb72290 0xb1565876 0xf5fee756 0x8ea9bef4 0x6ae96e0d 0x32148e17 0xf9531ec9 Figure 7: ChaCha20 output matrix for encrypting the packet length Miller, et al. Expires 18 September 2025 [Page 10] Internet-Draft SSH chacha20-poly1305 March 2025 To encrypt the 32-bit length field, only 32 bits of this cipher stream are required. The first word, 0xaccc3e2c, is encoded little- endian into the four bytes 2c 3e cc ac, and these are XORed with the big-endian SSH length field 00 00 00 48 to produce the encrypted length field 2c 3e cc e4. 2c 3e cc e4 Figure 8: Encrypted bytes of the packet length field The remaining 60 bytes of this output block are discarded. When encrypting the length field of the next packet, a fresh data block will be generated using that packet's sequence number. To encrypt the remainder of the packet, two cipher blocks are required. These are generated from the first 32 bytes of the cipher key data, and have block counter values 1 and 2 (value 0 is used to generate the MAC input). The two matrices input to ChaCha20 are therefore as follows, differing only in the block counter at the start of the bottom row: 0x61707865 0x3320646e 0x79622d32 0x6b206574 0x85f6bf8b 0x3302c15f 0x733e378c 0x14c9c0aa 0x05a976f0 0x324a44b2 0xeaffcaee 0xc5ec2be2 0x00000001 0x00000000 0x00000000 0x07000000 0x61707865 0x3320646e 0x79622d32 0x6b206574 0x85f6bf8b 0x3302c15f 0x733e378c 0x14c9c0aa 0x05a976f0 0x324a44b2 0xeaffcaee 0xc5ec2be2 0x00000002 0x00000000 0x00000000 0x07000000 Figure 9: ChaCha20 preimage matrices for encrypting the main packet data The ChaCha20 permutation transforms these two matrices into the following output blocks: 0x8905e2a3 0x7b7af05b 0xa9fa6ea9 0x5cc14cfa 0xc2f3c7ea 0x88a92e6d 0x25b5c029 0xee0caac8 0x57e5cf62 0x54d6a747 0x055c2b83 0x11c56757 0x2c0b08c4 0x02606ea4 0xfea28051 0xee4eabfc 0x69c3a5f4 0xb55efbdd 0x80a9caea 0xf270c0a0 0xa45d5d78 0x0b44d75b 0xf75247b7 0xe14c0e37 0x98039827 0xd8b8e8de 0xbf7035b6 0xc90bef5b 0x33e3c45a 0x51418cf6 0xcafeae62 0x6da70d32 Miller, et al. Expires 18 September 2025 [Page 11] Internet-Draft SSH chacha20-poly1305 March 2025 Figure 10: ChaCha20 output matrices for encrypting the main packet data These blocks are converted back into bytes in little-endian encoding, to create 128 bytes of data beginning a3 e2 05 89 ... and ending ... 32 0d a7 6d. The 72 bytes of packet data (apart from the separately encrypted length field) are XORed with the first 72 bytes of this data to produce the following encrypted output: a5 bc 05 89 5b f0 7a 7b a9 56 b6 c6 88 29 ac 7c 83 b7 80 b7 00 0e cd e7 45 af c7 05 bb c3 78 ce 03 a2 80 23 6b 87 b5 3b ed 58 39 66 23 02 b1 64 b6 28 6a 48 cd 1e 09 71 38 e3 cb 90 9b 8b 2b 82 9d d1 8d 2a 35 ff 82 d9 Figure 11: Encrypted bytes of the packet, excluding the length field in which, for example, the first byte 0xa5 is the bitwise XOR of the first cipher stream byte 0xa3 with the byte 0x06 from the cleartext packet (indicating the number of padding bytes). The encrypted length field is prefixed to the above, to produce the complete 76-byte ciphertext: 2c 3e cc e4 a5 bc 05 89 5b f0 7a 7b a9 56 b6 c6 88 29 ac 7c 83 b7 80 b7 00 0e cd e7 45 af c7 05 bb c3 78 ce 03 a2 80 23 6b 87 b5 3b ed 58 39 66 23 02 b1 64 b6 28 6a 48 cd 1e 09 71 38 e3 cb 90 9b 8b 2b 82 9d d1 8d 2a 35 ff 82 d9 Figure 12: Encrypted bytes of the whole packet, including its length This ciphertext is the input to the Poly1305 MAC, which is computed as follows. The packet data is converted into the following sequence of polynomial coefficients, by repeatedly taking a maximum of 16 bytes from the start of the data, appending the byte 0x01, and decoding as a little-endian integer: C[1] = 0x1c6b656a97b7af05b8905bca5e4cc3e2c C[2] = 0x105c7af45e7cd0e00b780b7837cac2988 C[3] = 0x1663958ed3bb5876b2380a203ce78c3bb C[4] = 0x190cbe33871091ecd486a28b664b10223 C[5] = 0x1d982ff352a8dd19d822b8b9b Figure 13: Poly1305 coefficients derived from the encrypted packet Miller, et al. Expires 18 September 2025 [Page 12] Internet-Draft SSH chacha20-poly1305 March 2025 The MAC key is constructed by generating a block of ChaCha20 cipher stream, using the same cipher that encrypted most of the packet, with a block counter value of 0. So the input to the ChaCha20 transformation is the following matrix: 0x61707865 0x3320646e 0x79622d32 0x6b206574 0x85f6bf8b 0x3302c15f 0x733e378c 0x14c9c0aa 0x05a976f0 0x324a44b2 0xeaffcaee 0xc5ec2be2 0x00000000 0x00000000 0x00000000 0x07000000 Figure 14: ChaCha20 preimage matrix for keying the MAC and the ChaCha20 permutation transforms it into this: 0xfba86ef6 0x046d187a 0xa6b4d75d 0xa4487348 0xebc13a8f 0xe0be63fa 0x65a5e1c1 0xdd5b9fd0 0x95f6ca26 0x509e2eec 0xb9f34fe2 0xc565e785 0xd52da783 0xc8f24915 0xb3907730 0x1da12e04 Figure 15: ChaCha20 output matrix for keying the MAC The top row of this matrix is converted into a 128-bit integer by recombining the four words in little-endian order, to make 0xa4487348a6b4d75d046d187afba86ef6. This is transformed into the Poly1305 integer 'r' at which the polynomial is evaluated, by computing its bitwise AND with the integer 0x0FFFFFFC0FFFFFFC0FFFFFFC0FFFFFFF. The result is r = 0x0448734806b4d75c046d18780ba86ef6. The second row of the matrix is similarly converted into a 128-bit integer 0xdd5b9fd065a5e1c1e0be63faebc13a8f, which is used as the mask value 'n' added at the end of the computation. The remaining two rows of the ChaCha20 output are discarded. The Poly1305 MAC is constructed by calculating the least non-negative residue mod 2^130-5 of the following expression: C[1] * r^5 + C[2] * r^4 + C[3] * r^3 + C[4] * r^[2] + C[5] * r Figure 16: Polynomial expression evaluated while computing Poly1305 The output of this computation is the integer 0x2db8d08018cd015cc486e8c6099dcfa06. This is reduced mod 2^128 to obtain 0xdb8d08018cd015cc486e8c6099dcfa06, which is then added modulo 2^128 to the nonce value 0xdd5b9fd065a5e1c1e0be63faebc13a8f, giving 0xb8e8a7d1f275f78e292cf05b859e3495. This is encoded as a 16-bit little-endian integer to give the final authentication tag: Miller, et al. Expires 18 September 2025 [Page 13] Internet-Draft SSH chacha20-poly1305 March 2025 95 34 9e 85 5b f0 2c 29 8e f7 75 f2 d1 a7 e8 b8 Figure 17: Bytes of the final Poly1305 authentication tag The full encrypted and authenticated data of this packet, sent over the TCP connection to the SSH server, is constructed by concatenating the encrypted length field, the rest of the encrypted packet data, and the authentication tag, and is as follows: 2c 3e cc e4 a5 bc 05 89 5b f0 7a 7b a9 56 b6 c6 88 29 ac 7c 83 b7 80 b7 00 0e cd e7 45 af c7 05 bb c3 78 ce 03 a2 80 23 6b 87 b5 3b ed 58 39 66 23 02 b1 64 b6 28 6a 48 cd 1e 09 71 38 e3 cb 90 9b 8b 2b 82 9d d1 8d 2a 35 ff 82 d9 95 34 9e 85 5b f0 2c 29 8e f7 75 f2 d1 a7 e8 b8 Figure 18: Full wire format of the packet, including the MAC Authors' Addresses Damien Miller OpenSSH Email: djm@mindrot.org Simon Tatham PuTTY Email: anakin@pobox.com Simon Josefsson Independent Email: simon@josefsson.org Miller, et al. Expires 18 September 2025 [Page 14]