Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add chacha20/poly1305 and chacha20poly1305_AEAD from openssh #14050

Conversation

jonasschnelli
Copy link
Contributor

This adds ChaCha20 and Poly1305 and the openSSH form of the AEAD.

The implementations of ChaCha20 are from DJB himself and directly taken (unchanged as much as possible) from the openSSH source code: https://github.com/openssh/openssh-portable/blob/master/chacha.c

Poly1305 is written by Andrew Moon is also directly taken (unchanged as much as possible) from the openSSH source code: https://github.com/openssh/openssh-portable/blob/master/poly1305.c

The code for the ChaCha20/Poly1305@openssh AEAD is taken from https://github.com/openssh/openssh-portable/blob/master/cipher-chachapoly.c with minimal changes.

More details on the AEAD construction:
https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.chacha20poly1305
https://gist.github.com/jonasschnelli/c530ea8421b8d0e80c51486325587c52

Test vectors are taken from the RFC draft:
https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7

Taking existing implementations should reduce risks of screwing up at the implementation level.

OUT OF SCOPE:

  • AVX,SSE acceleration (possible, see libsodium a.s.o.)
  • To Bitcoin Core adjusted C++ implementations
  • Combining with the existing ChaCha20 RNG
    (can all be done later, after verification of the correctness)

This is a subset of #14032 and a pre-requirement for BIP151.

@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 24, 2018

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #15649 (Add ChaCha20Poly1305@Bitcoin AEAD by jonasschnelli)
  • #15519 (Add Poly1305 implementation by jonasschnelli)
  • #15512 (Add ChaCha20 encryption option (XOR) by jonasschnelli)
  • #14047 (Add HKDF_HMAC256_L32 and method to negate a private key by jonasschnelli)
  • #14032 (Add p2p layer encryption with ECDH/ChaCha20Poly1305 by jonasschnelli)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@DesWurstes
Copy link
Contributor

Why not reuse the existing ChaCha20?

@laanwj laanwj added the P2P label Aug 25, 2018
@jonasschnelli
Copy link
Contributor Author

@DesWurstes: see PR description (out of scope).

@jonasschnelli
Copy link
Contributor Author

Added benchmark for the AEAD (and for direct comparison also added the dbl-SHA (HASH) benchmark).
Benchmarking 1MB data as well as 256bytes.

My system reports (!we compare SSE4 SHA256 vs non-optimized chacha20):

# Benchmark, evals, iterations, total, min, max, median
CHACHA20POLY1305AEAD_BIG, 5, 340, 3.68279, 0.00215035, 0.00219169, 0.00216025
CHACHA20POLY1305AEAD_SMALL, 5, 250000, 1.08673, 8.51516e-07, 8.93585e-07, 8.61119e-07
HASH256_BIG, 5, 340, 3.81384, 0.00222589, 0.00226436, 0.00224086
HASH256_SMALL, 5, 250000, 1.1305, 8.96669e-07, 9.15482e-07, 9.03866e-07

@jonasschnelli jonasschnelli force-pushed the 2018/08/bip151_chachapoly1305 branch 5 times, most recently from fcfa804 to 90702f4 Compare August 28, 2018 19:14
jonasschnelli added a commit to jonasschnelli/bitcoin that referenced this pull request Aug 29, 2018
might try to eliminate "superfluous" memsets. If there's an easy way to
detect memset_s, it would be better to use that. */
#if defined(_MSC_VER)
SecureZeroMemory(ptr, len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems this should include windows.h

@jonasschnelli jonasschnelli force-pushed the 2018/08/bip151_chachapoly1305 branch 4 times, most recently from f42f6d5 to ac477bc Compare August 31, 2018 19:49
uint8_t *dest, const uint8_t *src, uint32_t len,
uint32_t aadlen, int is_encrypt);

// extracts the LE 24bit (3byte) length from the AAD and puts it into a uint32_t (host endiannes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo found by codespell: endiannes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re out of scope "Combining with the existing ChaCha20 RNG": perhaps you can add some tests to show they're identical?

*/

static const struct chacha20_testvector chacha20_testvectors[] = {
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be much easier to verify against the RFC document if you parse a hex string.

(p)[3] = (uint8_t)((v) >> 24); \
} while (0)

void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove the poly1305_init, poly1305_update, poly1305_finish separation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@Sjors Sjors Sep 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see, in that case the source code URL at the top of the file is confusing; probably should add a link to Moons' implementation instead / in addition.

x->input[3] = U8TO32_LITTLE(constants + 12);
}

void chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) {
Copy link
Member

@Sjors Sjors Sep 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can confirm this function in 09ec49ba31867187cecd631593d37bcc5f3ca72f is identical to the original at de624c626ea081929df000b09932dbc804eda51d, modulo some whitespace.

@jonasschnelli
Copy link
Contributor Author

@Sjors The existing ChaCha20 implementation doesn't do the XORing and can therefore only be used for the RNG.

@sipa
Copy link
Member

sipa commented Sep 2, 2018 via email

@jonasschnelli
Copy link
Contributor Author

@sipa: agree. Though as written in the PR description. I'd like to keep the code (extracted from openSSH) as identical as possible. I think (or hope) we can do refactoring after this has been merged.

chacha_ivsetup(&ctx->header_ctx, (uint8_t *)&seqnr64, NULL);
chacha_encrypt_bytes(&ctx->header_ctx, ciphertext, buf, 3);
*len24_out = 0;
*len24_out = buf[0] | (buf[1] << 8) | (buf[2] << 16);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a mistake? *len24_out is assigned twice? *len24_out = 0; should be removed? :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if applying 3 time a uint_8t (24bits) the way its done here will guarantee to set the other 8 bits to 0. This is why I initialise with 0, then set bit 0 to 23. Could be that I'm wrong though.

Copy link
Contributor

@practicalswift practicalswift Oct 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wouldn't initialise before assignment if the RHS was an integer, right? :-)

buf[0] | (buf[1] << 8) | (buf[2] << 16) evaluates to an integer.

But don't trust me – I'm just a fellow human.

Let's verify using our favourite C++ interpreter cling:

$ cling

****************** CLING ******************
* Type C++ code and press enter to run it *
*             Type .q to exit             *
*******************************************
[cling]$ typeid(1).name()
(const char *) "i"
[cling]$ #include <cstdint>
[cling]$ uint8_t buf[3] = {1, 2, 3}
(uint8_t [3]) { '0x01', '0x02', '0x03' }
[cling]$ typeid(buf[0] | (buf[1] << 8) | (buf[2] << 16)).name()
(const char *) "i"
[cling]$ buf[0] | (buf[1] << 8) | (buf[2] << 16)
(int) 197121

:-)

assert(out_len == 255);
chacha20poly1305_crypt(&aead_ctx, seqnr, plaintext_buf_new, ciphertext_buf,
252, 3, 0);
assert(memcmp(plaintext_buf, plaintext_buf_new, 252) == 0);
Copy link
Contributor

@practicalswift practicalswift Sep 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be assert(memcmp(plaintext_buf, plaintext_buf_new, 255) == 0); or assert(memcmp(plaintext_buf, plaintext_buf_new, sizeof(plaintext_buf)) == 0);?

uint32_t aadlen, int is_encrypt) {
const uint8_t one[8] = {1, 0, 0, 0, 0, 0, 0, 0}; /* NB little-endian */
uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
int r = -1;
Copy link
Contributor

@practicalswift practicalswift Sep 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a dead store :-)

Initialize to zero instead and remove the r = 0 below?

@jonasschnelli
Copy link
Contributor Author

Fixed points reported by @practicalswift

@practicalswift
Copy link
Contributor

I'm afraid this PR doesn't compile when rebased on master

@jonasschnelli
Copy link
Contributor Author

Partially superseded by #15512 (the ChaCha20 part)

@jonasschnelli
Copy link
Contributor Author

Closing...
It's now replaced with #15512, #15519 and #15649.

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
No open projects
Status: Closed unmerged (Superseded)
Development

Successfully merging this pull request may close these issues.

8 participants