From mfriedl at gmail.com Fri Nov 1 21:24:51 2013 From: mfriedl at gmail.com (Markus Friedl) Date: Fri, 1 Nov 2013 11:24:51 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> Message-ID: Here are three versions (patch against openbsd cvs) 1) repace nacl w/libsodium, so i could test 2) curve25519-donna 3) Matthew's public domain reference implementation. i'd vote for #3 -------------- next part -------------- Am 30.10.2013 um 07:27 schrieb Damien Miller : > On Tue, 24 Sep 2013, Aris Adamantiadis wrote: > >> Dear OpenSSH developers, >> >> I've worked this week on an alternative key exchange mechanism, in >> reaction to the whole NSA leaks and claims over cryptographic backdoors >> and/or cracking advances. The key exchange is in my opinion the most >> critical defense against passive eavesdropping attacks. >> I believe Curve25519 from DJB can give users a secure alternative to >> classical Diffie-Hellman (with fixed groups or group exchanges) and >> NIST-approved elliptic curves. > > ... > > I just had a quick look at the patch. Overall it's good; some preliminary > comments below. > > diff --git a/kexc25519.c b/kexc25519.c > new file mode 100644 > index 0000000..8260fad > --- /dev/null > +++ b/kexc25519.c > ... > +#include > +#define CURVE25519_PUBKEY_SIZE crypto_scalarmult_curve25519_BYTES > > For OpenSSH, I think we could just include the portable C version from > https://code.google.com/p/curve25519-donna/ rather than depending on > the entirety of nacl. nacl includes a heap of stuff that we don't need > and makes some unusual design choices like choosing between native > implementations by measuring the host it is being compiled on. > > The downside to the -donna implementation is that it doesn't promise > constant time execution. AFAIK this isn't a killer for the SSH case as > an attacker doesn't get to measure the processing time for any set of DH > public values more than once. It would be worse if we reused DH values, > but we don't. (-donna also has the disadvantage of being slower, but were > quibbling over single-digit milliseconds here so IMO it doesn't matter at > all.) > > +void > +kex_c25519_hash( > + const EVP_MD *evp_md, > + char *client_version_string, > + char *server_version_string, > + char *ckexinit, int ckexinitlen, > + char *skexinit, int skexinitlen, > + u_char *serverhostkeyblob, int sbloblen, > + const unsigned char client_dh_pub[CURVE25519_PUBKEY_SIZE], > + const unsigned char server_dh_pub[CURVE25519_PUBKEY_SIZE], > + const BIGNUM *shared_secret, > ... > + buffer_put_bignum2(&b, shared_secret); > > It would be simpler to pass the shared_secret as a const u_char* and > length here - saving a round-trip to BIGNUM and back. > > diff --git a/kexc25519c.c b/kexc25519c.c > new file mode 100644 > index 0000000..b2000f0 > --- /dev/null > +++ b/kexc25519c.c > ... > +void > +kexc25519_client(Kex *kex) > +{ > ... > + /* generate private key */ > + for (i = 0; i < sizeof(client_key); i++) { > + if (i % 4 == 0) > + rnd = arc4random(); > + client_key[i] = rnd; > + rnd >>= 8; > + } > > easier to use arc4random_buf() here. If we use the -donna implementation > then we need to do the > > client_key[0] &= 248; > client_key[31] &= 127; > client_key[31] |= 64; > > ourselves. It might be better to have put a kex_c25519_genkey() in > kexc25519.c that does it all and use it in both the client and server. > > -d > From djm at mindrot.org Sat Nov 2 15:46:14 2013 From: djm at mindrot.org (Damien Miller) Date: Sat, 2 Nov 2013 15:46:14 +1100 (EST) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> Message-ID: On Fri, 1 Nov 2013, Markus Friedl wrote: > Here are three versions (patch against openbsd cvs) > > 1) repace nacl w/libsodium, so i could test > 2) curve25519-donna > 3) Matthew's public domain reference implementation. > > i'd vote for #3 Yes, me too. One thing: this patch will be incompatible with Aris' since we calculate the hash over the DH values encoded as strings rather than (as he does) bignums. IMO they should be strings because they aren't ever sent as bignums on the wire, but if the Curve25519 support is widely deployed then it might be too late to change. I don't think the encoding makes any appreciable difference to security - the bignum encoding is unambiguous. -d From manish.jagtap at airtightnetworks.com Sat Nov 2 15:46:56 2013 From: manish.jagtap at airtightnetworks.com (Manish Jagtap) Date: Sat, 2 Nov 2013 10:16:56 +0530 Subject: FIPS 140-2 patch for openssh 6.3.p1 In-Reply-To: <52720C99.6060501@suse.cz> References: <525626a6.a459440a.7091.337a@mx.google.com> <52720C99.6060501@suse.cz> Message-ID: <527483d4.43a3420a.6933.50c7@mx.google.com> Thanks Petr. 1. Can you please let us know ETA FIPS 140-2 patch for openssh 6.3p1? 2. Also, can you please check out following related thread? http://lists.mindrot.org/pipermail/openssh-unix-dev/2013-October/031746.html Is it because older clients are unaware of ECC ? Thanks, Manish -----Original Message----- From: Petr Cerny [mailto:pcerny at suse.cz] Sent: Thursday, October 31, 2013 1:24 PM To: openssh-unix-dev at mindrot.org Cc: Manish Jagtap Subject: Re: FIPS 140-2 patch for openssh 6.3.p1 Manish Jagtap wrote: > Hi, > > Is FIPS 140-2 patch for openssh 6.3.p1 available somewhere or do I have to > make one using > http://www.openssl.com/export/openssh/openssh-6.0p1.fips-revised.patch ? You can also look at the openSUSE package (https://build.opensuse.org/package/show/network/openssh) the patches you'd need are: openssh-6.2p2-fingerprint_hash.patch openssh-6.2p2-fips.patch Update to 6.3p1 is WIP. Kind regards Petr -- Petr Cerny Mozilla/OpenSSH maintainer for SUSE Linux From mfriedl at gmail.com Sat Nov 2 17:57:45 2013 From: mfriedl at gmail.com (Markus Friedl) Date: Sat, 2 Nov 2013 07:57:45 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> Message-ID: <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> It should be compatible with the original patch. However I think that the shared secret should be encoded as a string, too. What does libssh do? > Am 02.11.2013 um 05:46 schrieb Damien Miller : > >> On Fri, 1 Nov 2013, Markus Friedl wrote: >> >> Here are three versions (patch against openbsd cvs) >> >> 1) repace nacl w/libsodium, so i could test >> 2) curve25519-donna >> 3) Matthew's public domain reference implementation. >> >> i'd vote for #3 > > Yes, me too. > > One thing: this patch will be incompatible with Aris' since we calculate > the hash over the DH values encoded as strings rather than (as he does) > bignums. > > IMO they should be strings because they aren't ever sent as bignums on > the wire, but if the Curve25519 support is widely deployed then it might > be too late to change. I don't think the encoding makes any appreciable > difference to security - the bignum encoding is unambiguous. > > -d From mfriedl at gmail.com Sat Nov 2 20:07:05 2013 From: mfriedl at gmail.com (Markus Friedl) Date: Sat, 2 Nov 2013 10:07:05 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> References: <5241F449.8070407@0xbadc0de.be> <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> Message-ID: <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> if I understand http://git.libssh.org/projects/libssh.git/commit/?id=4cb6afcbd43ab503d4c3d3054b96a1492605ea8d correctly, then the shared secret is encoded as a bignum, probably because the rest of the code assumes it's a bignum (e.g. for key derivation, etc). however, the DH public keys are always encoded as strings (both in my patches and in the libssh.org code). Am 02.11.2013 um 07:57 schrieb Markus Friedl : > It should be compatible with the original patch. However I think that the shared secret should be encoded as a string, too. What does libssh do? > > > >> Am 02.11.2013 um 05:46 schrieb Damien Miller : >> >>> On Fri, 1 Nov 2013, Markus Friedl wrote: >>> >>> Here are three versions (patch against openbsd cvs) >>> >>> 1) repace nacl w/libsodium, so i could test >>> 2) curve25519-donna >>> 3) Matthew's public domain reference implementation. >>> >>> i'd vote for #3 >> >> Yes, me too. >> >> One thing: this patch will be incompatible with Aris' since we calculate >> the hash over the DH values encoded as strings rather than (as he does) >> bignums. >> >> IMO they should be strings because they aren't ever sent as bignums on >> the wire, but if the Curve25519 support is widely deployed then it might >> be too late to change. I don't think the encoding makes any appreciable >> difference to security - the bignum encoding is unambiguous. >> >> -d From aris at 0xbadc0de.be Sat Nov 2 21:38:48 2013 From: aris at 0xbadc0de.be (Aris Adamantiadis) Date: Sat, 02 Nov 2013 11:38:48 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> References: <5241F449.8070407@0xbadc0de.be> <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> Message-ID: <5274D638.8080000@0xbadc0de.be> Hi, That's indeed the case. It is described in http://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256 at libssh.org.txt The libssh code currently uses a bignum for k, but it can be modified if we reach a consensus. (curve25519 in libssh is in git master and did not yet make it into a release). I published this code here for feedback on the specs too so it is not to late to change. The reason I chose to encapsulate k into a bignum is because the procedure to generate the session keys, described in RFC 5656 point 4 and RFC4253 point 8.0 both describe K as a bignum. Now that I am reading the specs I notice I overlooked the others parameters to be either mpint (DH) or string (ecdh) depending on the situation. RFC4251 describes mpint to be multi-size and with positive values having MSB clear, so it's clearly incompatible with raw string. Since you both agreed on the curve25519 implementation to use, I'll work today on Markus' patch to make the changes Damien wanted. Aris Le 2/11/13 10:07, Markus Friedl a ?crit : > if I understand http://git.libssh.org/projects/libssh.git/commit/?id=4cb6afcbd43ab503d4c3d3054b96a1492605ea8d > correctly, then the shared secret is encoded as a bignum, > probably because the rest of the code assumes it's a bignum > (e.g. for key derivation, etc). however, the DH public keys > are always encoded as strings (both in my patches and > in the libssh.org code). > > > Am 02.11.2013 um 07:57 schrieb Markus Friedl : > >> It should be compatible with the original patch. However I think that the shared secret should be encoded as a string, too. What does libssh do? >> >> >> >>> Am 02.11.2013 um 05:46 schrieb Damien Miller : >>> >>>> On Fri, 1 Nov 2013, Markus Friedl wrote: >>>> >>>> Here are three versions (patch against openbsd cvs) >>>> >>>> 1) repace nacl w/libsodium, so i could test >>>> 2) curve25519-donna >>>> 3) Matthew's public domain reference implementation. >>>> >>>> i'd vote for #3 >>> Yes, me too. >>> >>> One thing: this patch will be incompatible with Aris' since we calculate >>> the hash over the DH values encoded as strings rather than (as he does) >>> bignums. >>> >>> IMO they should be strings because they aren't ever sent as bignums on >>> the wire, but if the Curve25519 support is widely deployed then it might >>> be too late to change. I don't think the encoding makes any appreciable >>> difference to security - the bignum encoding is unambiguous. >>> >>> -d From djm at mindrot.org Sat Nov 2 22:13:56 2013 From: djm at mindrot.org (Damien Miller) Date: Sat, 2 Nov 2013 22:13:56 +1100 (EST) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> References: <5241F449.8070407@0xbadc0de.be> <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> Message-ID: On Sat, 2 Nov 2013, Markus Friedl wrote: > if I understand http://git.libssh.org/projects/libssh.git/commit/?id=4cb6afcbd43ab503d4c3d3054b96a1492605ea8d > correctly, then the shared secret is encoded as a bignum, > probably because the rest of the code assumes it's a bignum > (e.g. for key derivation, etc). however, the DH public keys > are always encoded as strings (both in my patches and > in the libssh.org code). You're right - sorry I misread. -d From mfriedl at gmail.com Sat Nov 2 22:30:05 2013 From: mfriedl at gmail.com (Markus Friedl) Date: Sat, 2 Nov 2013 12:30:05 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <5274D638.8080000@0xbadc0de.be> References: <5241F449.8070407@0xbadc0de.be> <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> <5274D638.8080000@0xbadc0de.be> Message-ID: Am 02.11.2013 um 11:38 schrieb Aris Adamantiadis : > RFC4251 describes mpint to be multi-size and with positive values having > MSB clear, so it's clearly incompatible with raw string. > > Since you both agreed on the curve25519 implementation to use, I'll work > today on Markus' patch to make the changes Damien wanted. What do you want to change in my patch? I use string encoding for the pub keys both on the wire and for the hash. Only the shared secret uses mpint/bignum (for the hash). Should we use mpint everywhere? I don't think so as we can require strings if length 32 everywhere. So what would the be the consense? From djm at mindrot.org Sat Nov 2 22:33:16 2013 From: djm at mindrot.org (Damien Miller) Date: Sat, 2 Nov 2013 22:33:16 +1100 (EST) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> <5274D638.8080000@0xbadc0de.be> Message-ID: On Sat, 2 Nov 2013, Markus Friedl wrote: > Should we use mpint everywhere? > I don't think so as we can require strings if length 32 everywhere. I guess the question is this: do we treat curve25519 as a specific case of RFC5656 or as something different? Seen this way, I feel less strongly that the shared_secret should be a string. -d From aris at 0xbadc0de.be Sat Nov 2 22:51:40 2013 From: aris at 0xbadc0de.be (Aris Adamantiadis) Date: Sat, 02 Nov 2013 12:51:40 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> <688C4581-0AC8-4E2F-831D-5D297F793187@gmail.com> <9A7CA45D-B97C-4986-AE70-668FB6417990@gmail.com> <5274D638.8080000@0xbadc0de.be> Message-ID: <5274E74C.8090905@0xbadc0de.be> Le 2/11/13 12:30, Markus Friedl a ?crit : > Am 02.11.2013 um 11:38 schrieb Aris Adamantiadis : > >> RFC4251 describes mpint to be multi-size and with positive values having >> MSB clear, so it's clearly incompatible with raw string. >> >> Since you both agreed on the curve25519 implementation to use, I'll work >> today on Markus' patch to make the changes Damien wanted. > What do you want to change in my patch? > > I use string encoding for the pub keys both on the wire and for the hash. Only the shared secret uses mpint/bignum (for the hash). > > Should we use mpint everywhere? > I don't think so as we can require strings if length 32 everywhere. > > So what would the be the consense? Hi Markus, I wanted to change the arc4_random thing but just seen you already fixed it. I do not discuss the string encoding for pubkeys and hash, only for shared secret. Currently it's mpint, you were discussing of making it string. I just pointed out that RFC5656 tells: The hash H is formed by applying the algorithm HASH on a concatenation of the following: string V_C, client's identification string (CR and LF excluded) string V_S, server's identification string (CR and LF excluded) string I_C, payload of the client's SSH_MSG_KEXINIT string I_S, payload of the server's SSH_MSG_KEXINIT string K_S, server's public host key string Q_C, client's ephemeral public key octet string string Q_S, server's ephemeral public key octet string mpint K, shared secret So even tough public keys are points (x + y coordinates), the shared secret (x coordinate) is hashed as an mpint. If we look at curve25519 as a special case of RFC5656, the point and the x coordinate are the same. Aris From mfriedl at gmail.com Sun Nov 3 01:20:38 2013 From: mfriedl at gmail.com (Markus Friedl) Date: Sat, 2 Nov 2013 15:20:38 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <5274E74C.8090905@0xbadc0de.be> Message-ID: <20131102142038.GA22078@Markus-Friedls-MacBook-Air> On Sat, Nov 02, 2013 at 10:33:16PM +1100, Damien Miller wrote: > I guess the question is this: do we treat curve25519 as a specific case > of RFC5656 or as something different? I think we should treat it as a special case, pubkeys encoded as raw curve25519 strings> > Seen this way, I feel less strongly that the shared_secret should be a > string. shared_secret should be an mpint/bignum in the hash, since this is what the RFC requires for 'K', c.f. the SSH-ECDH RFC: http://tools.ietf.org/html/rfc5656#section-4 The elliptic curve public keys (points) that must be transmitted are encoded into octet strings before they are transmitted. The transformation between elliptic curve points and octet strings is specified in Sections 2.3.3 and 2.3.4 of [SEC1]; point compression MAY be used. The output of shared key generation is a field element xp. The SSH framework requires that the shared key be an integer. The conversion between a field element and an integer is specified in Section 2.3.9 of [SEC1]. where [SEC1] == http://www.secg.org/download/aid-780/sec1-v2.pdf And Aris just wrote: > I just pointed out that RFC5656 tells: > > The hash H is formed by applying the algorithm HASH on a > concatenation of the following: > > string V_C, client's identification string (CR and LF excluded) > string V_S, server's identification string (CR and LF excluded) > string I_C, payload of the client's SSH_MSG_KEXINIT > string I_S, payload of the server's SSH_MSG_KEXINIT > string K_S, server's public host key > string Q_C, client's ephemeral public key octet string > string Q_S, server's ephemeral public key octet string > mpint K, shared secret > > So even tough public keys are points (x + y coordinates), the shared > secret (x coordinate) is hashed as an mpint. If we look at curve25519 as > a special case of RFC5656, the point and the x coordinate are the same. so I think we should keep the encodings from the patch... -m From aris at 0xbadc0de.be Sun Nov 3 01:25:29 2013 From: aris at 0xbadc0de.be (Aris Adamantiadis) Date: Sat, 02 Nov 2013 15:25:29 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <20131102142038.GA22078@Markus-Friedls-MacBook-Air> References: <20131102142038.GA22078@Markus-Friedls-MacBook-Air> Message-ID: <52750B59.8080004@0xbadc0de.be> > shared_secret should be an mpint/bignum in the hash, since > this is what the RFC requires for 'K', c.f. the SSH-ECDH RFC: > > http://tools.ietf.org/html/rfc5656#section-4 > The elliptic curve public keys (points) that must be transmitted are > encoded into octet strings before they are transmitted. The > transformation between elliptic curve points and octet strings is > specified in Sections 2.3.3 and 2.3.4 of [SEC1]; point compression > MAY be used. The output of shared key generation is a field element > xp. The SSH framework requires that the shared key be an integer. > The conversion between a field element and an integer is specified in > Section 2.3.9 of [SEC1]. > where [SEC1] == http://www.secg.org/download/aid-780/sec1-v2.pdf > > I think [SEC1] is irrelevant here since Curve25519 is defined somewhere else. I think the key here is "The SSH framework requires that the shared key be an integer" which I do not believe to be a MUST, but a reason enough to keep an mpint. > so I think we should keep the encodings from the patch... > > -m > So I think the patch is ready :) Aris From djm at mindrot.org Sun Nov 3 07:58:11 2013 From: djm at mindrot.org (Damien Miller) Date: Sun, 3 Nov 2013 07:58:11 +1100 (EST) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <20131102142038.GA22078@Markus-Friedls-MacBook-Air> References: <20131102142038.GA22078@Markus-Friedls-MacBook-Air> Message-ID: On Sat, 2 Nov 2013, Markus Friedl wrote: > > So even tough public keys are points (x + y coordinates), the shared > > secret (x coordinate) is hashed as an mpint. If we look at curve25519 as > > a special case of RFC5656, the point and the x coordinate are the same. > > so I think we should keep the encodings from the patch... yes. Patch is ok djm@ From mancha1 at hush.com Tue Nov 5 05:57:29 2013 From: mancha1 at hush.com (mancha) Date: Mon, 04 Nov 2013 18:57:29 +0000 Subject: Portable CVS repo problems Message-ID: <20131104185729.7817E20360@smtp.hushmail.com> Hello. While syncing OpenSSH portable CVS I received: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the ECDSA key sent by the remote host is d0:46:24:c1:63:cf:6b:f2:e3:33:3d:15:62:08:53:72. Please contact your system administrator. [EDIT] ECDSA host key for anoncvs.mindrot.org has changed and you have requested strict checking. Host key verification failed. Please confirm/deny the key change. --mancha PS If this change is valid, can you please give details on how to track these changes in the future? From imorgan at nas.nasa.gov Tue Nov 5 07:01:16 2013 From: imorgan at nas.nasa.gov (Iain Morgan) Date: Mon, 4 Nov 2013 12:01:16 -0800 Subject: Portable CVS repo problems In-Reply-To: <20131104185729.7817E20360@smtp.hushmail.com> References: <20131104185729.7817E20360@smtp.hushmail.com> Message-ID: <20131104200116.GD8747@linux124.nas.nasa.gov> I likewise notifced this. A similar situation happend back in July and the offered key has the same fingerpint is identical. I've quoted the explanation from the previous occurrence below: By way of explanation: I run a separate sshd for the anoncvs service and I forgot to restart it, so connections were falling through to the wildcard-bound main sshd. On Mon, Nov 04, 2013 at 18:57:29 +0000, mancha wrote: > Hello. While syncing OpenSSH portable CVS I received: > > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ > @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ > IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! > Someone could be eavesdropping on you right now (man-in-the-middle > attack)! > It is also possible that a host key has just been changed. > The fingerprint for the ECDSA key sent by the remote host is > d0:46:24:c1:63:cf:6b:f2:e3:33:3d:15:62:08:53:72. > Please contact your system administrator. > [EDIT] > ECDSA host key for anoncvs.mindrot.org has changed and you have > requested strict checking. > Host key verification failed. > > Please confirm/deny the key change. > > --mancha > > PS If this change is valid, can you please give details on how > to track these changes in the future? > > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- Iain Morgan From mancha1 at hush.com Tue Nov 5 07:40:42 2013 From: mancha1 at hush.com (mancha) Date: Mon, 4 Nov 2013 20:40:42 +0000 (UTC) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal References: <5241F449.8070407@0xbadc0de.be> Message-ID: Aris Adamantiadis 0xbadc0de.be> writes: > I've worked this week on an alternative key exchange mechanism, in > reaction to the whole NSA leaks and claims over cryptographic backdoors > and/or cracking advances... > I believe Curve25519 from DJB can give users a secure alternative to > classical Diffie-Hellman (with fixed groups or group exchanges) and > NIST-approved elliptic curves. Damien Miller mindrot.org> writes: > I'm interested in supporting ed25519 as a key algorithm, EC-DH in > curve25519 and ChaCha/Salsa20+poly1305 as an AEAD cipher+MAC. Just need > to figure out when and how :) Hello. I applaud the interest in augmenting the set of key exchange algos from dhg1,dhg14,dhgex,p256,p384,p521) to include a DJB-sanctioned curve. I do have a few questions... 1. Why is Curve25519 receiving more attention than other Bernstein recommendations such as: Curve2213, Curve1174, Curve383187, and Curve3617? Is it as simple as there being a 25519 implementation readily available in NaCl? 2. Those 5 curves have received Bernstein's seal of approval based on a set of criteria he refers to as twists, completeness, etc. What other academic review of ECC should be taken into account? 3. Has similar consideration been given to encryption ciphers? For starters, has inclusion of any "optional" ciphers per RFC 4253/4344 (blowfish-ctr, twofish{128,192,256}-{cbc,ctr}, serpent{128,192,256}-{cbc,ctr}, cast128-ctr) been contemplated? Thanks! --mancha From mancha1 at hush.com Tue Nov 5 07:51:09 2013 From: mancha1 at hush.com (mancha) Date: Mon, 4 Nov 2013 20:51:09 +0000 (UTC) Subject: Portable CVS repo problems References: <20131104185729.7817E20360@smtp.hushmail.com> <20131104200116.GD8747@linux124.nas.nasa.gov> Message-ID: Iain Morgan nas.nasa.gov> writes: > > I likewise notifced this. A similar situation happend back in July and > the offered key has the same fingerpint is identical. I've quoted the > explanation from the previous occurrence below: > > By way of explanation: I run a separate sshd for the anoncvs > service and I forgot to restart it, so connections were > falling through to the wildcard-bound main sshd. > Thank you for posting that; it puts my mind at ease. I think I'll just wait for anoncvs's daemon to be restarted to not mess with known_hosts. --mancha From azet at azet.org Tue Nov 5 21:57:04 2013 From: azet at azet.org (Aaron Zauner) Date: Tue, 5 Nov 2013 11:57:04 +0100 Subject: ssh-keygen DSA keylenght limit Message-ID: Dear OpenSSH Developers, I am wondering as to why there is a 1024 bit limitation in the `ssh-keygen` tool up until the current CVS version. There seem to be far higher bit rates when it comes to ECDSA. This effectively limits e.g. DSA host key generation on all BSD and Linux systems as of today. ssh-keygen.c (CVS) - starting with line 181: ``` if (type == KEY_DSA && *bitsp != 1024) fatal("DSA keys must be 1024 bits"); else if (type != KEY_ECDSA && *bitsp < 768) fatal("Key must at least be 768 bits"); else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1) fatal("Invalid ECDSA key length - valid lengths are " "256, 384 or 521 bits?); ``` Now the current NIST/FIPS recommendation for 2010 and onwards suggests using 2048bit+ keys: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - 4.2 Selection of Parameter Sizes and Hash Functions for DSA I might be missing something so I am curious if there was a specific reason to disable generation of 1024+bit keys or if that was just forgotten during development? Thanks for your time, Aaron -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 1091 bytes Desc: Message signed with OpenPGP using GPGMail URL: From azet at azet.org Tue Nov 5 22:11:40 2013 From: azet at azet.org (Aaron Zauner) Date: Tue, 5 Nov 2013 12:11:40 +0100 Subject: ssh-keygen DSA keylenght limit In-Reply-To: References: Message-ID: On 05 Nov 2013, at 11:57, Aaron Zauner wrote: > There seem to be far higher bit rates when it comes to ECDSA. Read: higher comparable security. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 1091 bytes Desc: Message signed with OpenPGP using GPGMail URL: From dtucker at zip.com.au Tue Nov 5 22:23:39 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Tue, 5 Nov 2013 22:23:39 +1100 Subject: ssh-keygen DSA keylenght limit In-Reply-To: References: Message-ID: <20131105112339.GA15586@gate.dtucker.net> On Tue, Nov 05, 2013 at 11:57:04AM +0100, Aaron Zauner wrote: > I am wondering as to why there is a 1024 bit limitation in the > `ssh-keygen` tool up until the current CVS version. [...] It's deliberate. RFC4253 requires the use of SHA1 for DSA keys and FIPS-186-3 requires the use of a longer hash than SHA1 for keys larger than 1024 bits. The only way to comply with both is to allow only keys that are 1024 bits. See https://bugzilla.mindrot.org/show_bug.cgi?id=1647 for further info. -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From cu.truong at atos.net Tue Nov 5 21:34:08 2013 From: cu.truong at atos.net (Truong, Van Cu) Date: Tue, 5 Nov 2013 10:34:08 +0000 Subject: OpenSSH with PAM for HP-UX Message-ID: <51D043D3C285E449AA3178ADB8CAD9602DCBF81F@DEFTHW99EZ4MSX.ww931.my-it-solutions.net> Dear Openssh developer, I've got some trouble by using openssh with UsePAM=yes on HP-UX. The problem is, when password of some user expired, he can't set a new password. Details about the issue. - HP-UX: B.11.31 U 9000/800 206109309 unlimited-user license - Openssh Version: 6.2p2 (same problem with 6.0p1) - sshd_config Protocol 2 PrintMotd yes Subsystem sftp /opt/openssh/libexec/sftp-server XAuthLocation /usr/bin/X11/xauth LogLevel VERBOSE StrictModes no UsePAM yes X11Forwarding yes AllowTcpForwarding yes X11UseLocalhost yes UsePrivilegeSeparation yes MaxAuthTries 12 - /etc/pam.conf (only sshd sector) sshd auth required libpam_hpsec.so.1 debug sshd auth required libpam_unix.so.1 debug sshd account required libpam_hpsec.so.1 debug sshd account required libpam_unix.so.1 debug sshd session required libpam_hpsec.so.1 debug sshd session required libpam_unix.so.1 debug sshd password required libpam_hpsec.so.1 debug sshd password required libpam_unix.so.1 debug Now an user tried to login with expired password: ssh test at qachp06 Password: Changing password for test Old password: New password: Connection closed by 10.86.88.101 The same scenario in debug modus On the client side: #ssh -vvv test at qachp06 -p 2222 OpenSSH_5.5p1, OpenSSL 0.9.8n 24 Mar 2010 debug1: Reading configuration data /user/cu/.ssh/config debug1: Reading configuration data /etc/openssh/ssh_config debug2: ssh_connect: needpriv 0 debug1: Connecting to qachp06 [10.86.88.101] port 2222. debug1: Connection established. debug1: could not open key file '/etc/openssh/ssh_host_key': Permission denied debug1: could not open key file '/etc/openssh/ssh_host_dsa_key': Permission denied debug1: could not open key file '/etc/openssh/ssh_host_rsa_key': Permission denied debug3: Not a RSA1 key file /user/cu/.ssh/id_rsa. debug2: key_type_from_name: unknown key type '-----BEGIN' debug3: key_read: missing keytype debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug2: key_type_from_name: unknown key type '-----END' debug3: key_read: missing keytype debug1: identity file /user/cu/.ssh/id_rsa type 1 debug1: identity file /user/cu/.ssh/id_rsa-cert type -1 debug3: Not a RSA1 key file /user/cu/.ssh/id_dsa. debug2: key_type_from_name: unknown key type '-----BEGIN' debug3: key_read: missing keytype debug2: key_type_from_name: unknown key type 'Proc-Type:' debug3: key_read: missing keytype debug2: key_type_from_name: unknown key type 'DEK-Info:' debug3: key_read: missing keytype debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug3: key_read: missing whitespace debug2: key_type_from_name: unknown key type '-----END' debug3: key_read: missing keytype debug1: identity file /user/cu/.ssh/id_dsa type 2 debug1: identity file /user/cu/.ssh/id_dsa-cert type -1 debug1: Remote protocol version 2.0, remote software version OpenSSH_6.2 debug1: match: OpenSSH_6.2 pat OpenSSH* debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_5.5 debug2: fd 4 setting O_NONBLOCK debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug2: kex_parse_kexinit: diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 debug2: kex_parse_kexinit: ssh-rsa-cert-v00 at openssh.com,ssh-dss-cert-v00 at openssh.com,ssh-rsa,ssh-dss debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se debug2: kex_parse_kexinit: hmac-md5,hmac-sha1,umac-64 at openssh.com,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: hmac-md5,hmac-sha1,umac-64 at openssh.com,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: first_kex_follows 0 debug2: kex_parse_kexinit: reserved 0 debug2: kex_parse_kexinit: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 debug2: kex_parse_kexinit: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256 debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm at openssh.com,aes256-gcm at openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm at openssh.com,aes256-gcm at openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: none,zlib at openssh.com debug2: kex_parse_kexinit: none,zlib at openssh.com debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: first_kex_follows 0 debug2: kex_parse_kexinit: reserved 0 debug2: mac_setup: found hmac-md5 debug1: kex: server->client aes128-ctr hmac-md5 none debug2: mac_setup: found hmac-md5 debug1: kex: client->server aes128-ctr hmac-md5 none debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP debug2: dh_gen_key: priv key bits set: 122/256 debug2: bits set: 495/1024 debug1: SSH2_MSG_KEX_DH_GEX_INIT sent debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY debug3: put_host_port: [10.86.88.101]:2222 debug3: put_host_port: [qachp06]:2222 debug3: check_host_in_hostfile: host [qachp06]:2222 filename /user/cu/.ssh/known_hosts2 debug3: check_host_in_hostfile: host [qachp06]:2222 filename /user/cu/.ssh/known_hosts2 debug3: check_host_in_hostfile: host [qachp06]:2222 filename /etc/openssh/ssh_known_hosts2 debug3: check_host_in_hostfile: host [qachp06]:2222 filename /etc/openssh/ssh_known_hosts2 debug1: checking without port identifier debug3: check_host_in_hostfile: host qachp06 filename /user/cu/.ssh/known_hosts2 debug3: check_host_in_hostfile: host qachp06 filename /user/cu/.ssh/known_hosts2 debug3: check_host_in_hostfile: host qachp06 filename /etc/openssh/ssh_known_hosts2 debug3: check_host_in_hostfile: host qachp06 filename /etc/openssh/ssh_known_hosts2 debug3: put_host_port: [10.86.88.101]:2222 debug3: put_host_port: [qachp06]:2222 debug3: check_host_in_hostfile: host [qachp06]:2222 filename /user/cu/.ssh/known_hosts debug3: check_host_in_hostfile: host [qachp06]:2222 filename /user/cu/.ssh/known_hosts debug3: check_host_in_hostfile: host [qachp06]:2222 filename /etc/openssh/ssh_known_hosts debug3: check_host_in_hostfile: host [qachp06]:2222 filename /etc/openssh/ssh_known_hosts debug1: checking without port identifier debug3: check_host_in_hostfile: host qachp06 filename /user/cu/.ssh/known_hosts debug3: check_host_in_hostfile: host qachp06 filename /user/cu/.ssh/known_hosts debug3: check_host_in_hostfile: match line 146 debug1: Host 'qachp06' is known and matches the RSA host key. debug1: Found key in /user/cu/.ssh/known_hosts:146 debug1: found matching key w/out port debug2: bits set: 547/1024 debug1: ssh_rsa_verify: signature correct debug2: kex_derive_keys debug2: set_newkeys: mode 1 debug1: SSH2_MSG_NEWKEYS sent debug1: expecting SSH2_MSG_NEWKEYS debug2: set_newkeys: mode 0 debug1: SSH2_MSG_NEWKEYS received debug1: Roaming not allowed by server debug1: SSH2_MSG_SERVICE_REQUEST sent debug2: service_accept: ssh-userauth debug1: SSH2_MSG_SERVICE_ACCEPT received debug2: key: /user/cu/.ssh/id_rsa (151f10) debug2: key: /user/cu/.ssh/id_dsa (152010) debug1: Authentications that can continue: publickey,password,keyboard-interactive debug3: start over, passed a different list publickey,password,keyboard-interactive debug3: preferred hostbased,publickey,keyboard-interactive,password debug3: authmethod_lookup publickey debug3: remaining preferred: keyboard-interactive,password debug3: authmethod_is_enabled publickey debug1: Next authentication method: publickey debug1: Offering public key: /user/cu/.ssh/id_rsa debug3: send_pubkey_test debug2: we sent a publickey packet, wait for reply debug1: Authentications that can continue: publickey,password,keyboard-interactive debug1: Offering public key: /user/cu/.ssh/id_dsa debug3: send_pubkey_test debug2: we sent a publickey packet, wait for reply debug1: Authentications that can continue: publickey,password,keyboard-interactive debug2: we did not send a packet, disable method debug3: authmethod_lookup keyboard-interactive debug3: remaining preferred: password debug3: authmethod_is_enabled keyboard-interactive debug1: Next authentication method: keyboard-interactive debug2: userauth_kbdint debug2: we sent a keyboard-interactive packet, wait for reply debug2: input_userauth_info_req debug2: input_userauth_info_req: num_prompts 1 Password: debug3: packet_send2: adding 32 (len 24 padlen 8 extra_pad 64) debug2: input_userauth_info_req debug2: input_userauth_info_req: num_prompts 1 Changing password for test Old password: debug3: packet_send2: adding 32 (len 24 padlen 8 extra_pad 64) debug2: input_userauth_info_req debug2: input_userauth_info_req: num_prompts 1 New password: debug3: packet_send2: adding 32 (len 23 padlen 9 extra_pad 64) Connection closed by 10.86.88.101 On the server side: #/opt/openssh/sbin/sshd -ddd -p 2222 debug2: load_server_config: filename /etc/openssh/sshd_config debug2: load_server_config: done config len = 272 debug2: parse_server_config: config /etc/openssh/sshd_config len 272 debug3: /etc/openssh/sshd_config:8 setting Protocol 2 debug3: /etc/openssh/sshd_config:9 setting PrintMotd yes debug3: /etc/openssh/sshd_config:10 setting XAuthLocation /usr/bin/X11/xauth debug3: /etc/openssh/sshd_config:11 setting Subsystem sftp /opt/openssh/libexec/sftp-server debug3: /etc/openssh/sshd_config:12 setting LogLevel VERBOSE debug3: /etc/openssh/sshd_config:13 setting StrictModes no debug3: /etc/openssh/sshd_config:14 setting UsePAM yes debug3: /etc/openssh/sshd_config:15 setting X11Forwarding yes debug3: /etc/openssh/sshd_config:16 setting AllowTcpForwarding yes debug3: /etc/openssh/sshd_config:17 setting X11UseLocalhost yes debug3: /etc/openssh/sshd_config:18 setting UsePrivilegeSeparation yes debug3: /etc/openssh/sshd_config:19 setting MaxAuthTries 12 debug1: sshd version OpenSSH_6.2, OpenSSL 1.0.1e 11 Feb 2013 debug3: Incorrect RSA1 identifier debug1: read PEM private key done: type RSA debug1: private host key: #0 type 1 RSA debug3: Incorrect RSA1 identifier debug1: read PEM private key done: type DSA debug1: private host key: #1 type 2 DSA debug3: Incorrect RSA1 identifier debug1: read PEM private key done: type ECDSA debug1: private host key: #2 type 3 ECDSA debug1: rexec_argv[0]='/opt/openssh/sbin/sshd' debug1: rexec_argv[1]='-ddd' debug1: rexec_argv[2]='-p' debug1: rexec_argv[3]='2222' debug2: fd 4 setting O_NONBLOCK debug3: sock_set_v6only: set socket 4 IPV6_V6ONLY debug1: Bind to port 2222 on ::. Server listening on :: port 2222. debug2: fd 5 setting O_NONBLOCK debug1: Bind to port 2222 on 0.0.0.0. Server listening on 0.0.0.0 port 2222. debug3: fd 6 is not O_NONBLOCK debug1: Server will not fork when running in debugging mode. debug3: send_rexec_state: entering fd = 9 config len 272 debug3: ssh_msg_send: type 0 debug3: send_rexec_state: done debug1: rexec start in 6 out 6 newsock 6 pipe -1 sock 9 debug1: inetd sockets after dupping: 4, 4 Connection from 139.25.181.1 port 55087 debug1: Client protocol version 2.0; client software version OpenSSH_5.5 debug1: match: OpenSSH_5.5 pat OpenSSH_5* debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_6.2 debug2: fd 4 setting O_NONBLOCK debug2: Network child is on pid 6144 debug3: preauth child monitor started debug3: privsep user:group 9999:9999 [preauth] debug1: permanently_set_uid: 9999/9999 [preauth] debug1: list_hostkey_types: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256 [preauth] debug1: SSH2_MSG_KEXINIT sent [preauth] debug1: SSH2_MSG_KEXINIT received [preauth] debug2: kex_parse_kexinit: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 [preauth] debug2: kex_parse_kexinit: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256 [preauth] debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm at openssh.com,aes256-gcm at openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se [preauth] debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm at openssh.com,aes256-gcm at openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se [preauth] debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 [preauth] debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 [preauth] debug2: kex_parse_kexinit: none,zlib at openssh.com [preauth] debug2: kex_parse_kexinit: none,zlib at openssh.com [preauth] debug2: kex_parse_kexinit: [preauth] debug2: kex_parse_kexinit: [preauth] debug2: kex_parse_kexinit: first_kex_follows 0 [preauth] debug2: kex_parse_kexinit: reserved 0 [preauth] debug2: kex_parse_kexinit: diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 [preauth] debug2: kex_parse_kexinit: ssh-rsa-cert-v00 at openssh.com,ssh-dss-cert-v00 at openssh.com,ssh-rsa,ssh-dss [preauth] debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se [preauth] debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se [preauth] debug2: kex_parse_kexinit: hmac-md5,hmac-sha1,umac-64 at openssh.com,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 [preauth] debug2: kex_parse_kexinit: hmac-md5,hmac-sha1,umac-64 at openssh.com,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 [preauth] debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib [preauth] debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib [preauth] debug2: kex_parse_kexinit: [preauth] debug2: kex_parse_kexinit: [preauth] debug2: kex_parse_kexinit: first_kex_follows 0 [preauth] debug2: kex_parse_kexinit: reserved 0 [preauth] debug2: mac_setup: found hmac-md5 [preauth] debug1: kex: client->server aes128-ctr hmac-md5 none [preauth] debug2: mac_setup: found hmac-md5 [preauth] debug1: kex: server->client aes128-ctr hmac-md5 none [preauth] debug1: SSH2_MSG_KEX_DH_GEX_REQUEST received [preauth] debug3: mm_request_send entering: type 0 [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 0 debug3: mm_answer_moduli: got parameters: 1024 1024 8192 debug3: mm_request_send entering: type 1 debug2: monitor_read: 0 used once, disabling now debug3: mm_choose_dh: waiting for MONITOR_ANS_MODULI [preauth] debug3: mm_request_receive_expect entering: type 1 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_choose_dh: remaining 0 [preauth] debug1: SSH2_MSG_KEX_DH_GEX_GROUP sent [preauth] debug2: dh_gen_key: priv key bits set: 141/256 [preauth] debug2: bits set: 547/1024 [preauth] debug1: expecting SSH2_MSG_KEX_DH_GEX_INIT [preauth] debug2: bits set: 495/1024 [preauth] debug3: mm_key_sign entering [preauth] debug3: mm_request_send entering: type 6 [preauth] debug3: mm_key_sign: waiting for MONITOR_ANS_SIGN [preauth] debug3: mm_request_receive_expect entering: type 7 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 6 debug3: mm_answer_sign debug3: mm_answer_sign: signature 40025f10(271) debug3: mm_request_send entering: type 7 debug2: monitor_read: 6 used once, disabling now debug1: SSH2_MSG_KEX_DH_GEX_REPLY sent [preauth] debug2: kex_derive_keys [preauth] debug2: set_newkeys: mode 1 [preauth] debug1: SSH2_MSG_NEWKEYS sent [preauth] debug1: expecting SSH2_MSG_NEWKEYS [preauth] debug2: set_newkeys: mode 0 [preauth] debug1: SSH2_MSG_NEWKEYS received [preauth] debug1: KEX done [preauth] debug1: userauth-request for user test service ssh-connection method none [preauth] debug1: attempt 0 failures 0 [preauth] debug3: mm_getpwnamallow entering [preauth] debug3: mm_request_send entering: type 8 [preauth] debug3: mm_getpwnamallow: waiting for MONITOR_ANS_PWNAM [preauth] debug3: mm_request_receive_expect entering: type 9 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 8 debug3: mm_answer_pwnamallow debug3: Trying to reverse map address 139.25.181.1. debug2: parse_server_config: config reprocess config len 272 debug3: mm_answer_pwnamallow: sending MONITOR_ANS_PWNAM: 1 debug3: mm_request_send entering: type 9 debug2: monitor_read: 8 used once, disabling now debug2: input_userauth_request: setting up authctxt for test [preauth] debug3: mm_start_pam entering [preauth] debug3: mm_request_send entering: type 100 [preauth] debug3: mm_inform_authserv entering [preauth] debug3: mm_request_send entering: type 4 [preauth] debug2: input_userauth_request: try method none [preauth] debug3: userauth_finish: failure partial=0 next methods="publickey,password,keyboard-interactive" [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 100 debug1: PAM: initializing for "test" debug1: PAM: setting PAM_RHOST to "139.25.181.1" debug2: monitor_read: 100 used once, disabling now debug1: userauth-request for user test service ssh-connection method publickey [preauth] debug1: attempt 1 failures 0 [preauth] debug2: input_userauth_request: try method publickey [preauth] debug1: test whether pkalg/pkblob are acceptable [preauth] debug3: mm_key_allowed entering [preauth] debug3: mm_request_send entering: type 22 [preauth] debug3: mm_key_allowed: waiting for MONITOR_ANS_KEYALLOWED [preauth] debug3: mm_request_receive_expect entering: type 23 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 4 debug3: mm_answer_authserv: service=ssh-connection, style= debug2: monitor_read: 4 used once, disabling now debug3: mm_request_receive entering debug3: monitor_read: checking request 22 debug3: mm_answer_keyallowed entering debug3: mm_answer_keyallowed: key_from_blob: 4002d5a0 debug1: temporarily_use_uid: 108/20 (e=0/3) debug1: trying public key file /home/test/.ssh/authorized_keys debug1: Could not open authorized keys '/home/test/.ssh/authorized_keys': No such file or directory debug1: restore_uid: 0/3 debug1: temporarily_use_uid: 108/20 (e=0/3) debug1: trying public key file /home/test/.ssh/authorized_keys2 debug1: Could not open authorized keys '/home/test/.ssh/authorized_keys2': No such file or directory debug1: restore_uid: 0/3 Failed publickey for test from 139.25.181.1 port 55087 ssh2 debug3: mm_answer_keyallowed: key 4002d5a0 is not allowed debug3: mm_request_send entering: type 23 debug2: userauth_pubkey: authenticated 0 pkalg ssh-rsa [preauth] debug3: userauth_finish: failure partial=0 next methods="publickey,password,keyboard-interactive" [preauth] debug1: userauth-request for user test service ssh-connection method publickey [preauth] debug1: attempt 2 failures 1 [preauth] debug2: input_userauth_request: try method publickey [preauth] debug1: test whether pkalg/pkblob are acceptable [preauth] debug3: mm_key_allowed entering [preauth] debug3: mm_request_send entering: type 22 [preauth] debug3: mm_key_allowed: waiting for MONITOR_ANS_KEYALLOWED [preauth] debug3: mm_request_receive_expect entering: type 23 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 22 debug3: mm_answer_keyallowed entering debug3: mm_answer_keyallowed: key_from_blob: 4002d480 debug1: temporarily_use_uid: 108/20 (e=0/3) debug1: trying public key file /home/test/.ssh/authorized_keys debug1: Could not open authorized keys '/home/test/.ssh/authorized_keys': No such file or directory debug1: restore_uid: 0/3 debug1: temporarily_use_uid: 108/20 (e=0/3) debug1: trying public key file /home/test/.ssh/authorized_keys2 debug1: Could not open authorized keys '/home/test/.ssh/authorized_keys2': No such file or directory debug1: restore_uid: 0/3 Failed publickey for test from 139.25.181.1 port 55087 ssh2 debug3: mm_answer_keyallowed: key 4002d480 is not allowed debug3: mm_request_send entering: type 23 debug2: userauth_pubkey: authenticated 0 pkalg ssh-dss [preauth] debug3: userauth_finish: failure partial=0 next methods="publickey,password,keyboard-interactive" [preauth] debug1: userauth-request for user test service ssh-connection method keyboard-interactive [preauth] debug1: attempt 3 failures 2 [preauth] debug2: input_userauth_request: try method keyboard-interactive [preauth] debug1: keyboard-interactive devs [preauth] debug1: auth2_challenge: user=test devs= [preauth] debug1: kbdint_alloc: devices 'pam' [preauth] debug2: auth2_challenge_start: devices pam [preauth] debug2: kbdint_next_device: devices [preauth] debug1: auth2_challenge_start: trying authentication method 'pam' [preauth] debug3: mm_sshpam_init_ctx [preauth] debug3: mm_request_send entering: type 104 [preauth] debug3: mm_sshpam_init_ctx: waiting for MONITOR_ANS_PAM_INIT_CTX [preauth] debug3: mm_request_receive_expect entering: type 105 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 104 debug3: mm_answer_pam_init_ctx debug3: PAM: sshpam_init_ctx entering debug3: mm_request_send entering: type 105 debug3: mm_sshpam_query [preauth] debug3: mm_request_send entering: type 106 [preauth] debug3: mm_sshpam_query: waiting for MONITOR_ANS_PAM_QUERY [preauth] debug3: mm_request_receive_expect entering: type 107 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 106 debug3: mm_answer_pam_query debug3: PAM: sshpam_query entering debug3: ssh_msg_recv entering debug3: PAM: sshpam_thread_conv entering, 1 messages debug3: ssh_msg_send: type 1 debug3: ssh_msg_recv entering debug3: mm_request_send entering: type 107 debug3: mm_sshpam_query: pam_query returned 0 [preauth] Postponed keyboard-interactive for test from 139.25.181.1 port 55087 ssh2 [preauth] debug3: mm_sshpam_respond [preauth] debug3: mm_request_send entering: type 108 [preauth] debug3: mm_sshpam_respond: waiting for MONITOR_ANS_PAM_RESPOND [preauth] debug3: mm_request_receive_expect entering: type 109 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 108 debug3: mm_answer_pam_respond debug2: PAM: sshpam_respond entering, 1 responses debug3: ssh_msg_send: type 6 debug3: mm_request_send entering: type 109 debug3: mm_sshpam_respond: pam_respond returned 1 [preauth] debug3: mm_sshpam_query [preauth] debug3: mm_request_send entering: type 106 [preauth] debug3: mm_sshpam_query: waiting for MONITOR_ANS_PAM_QUERY [preauth] debug3: mm_request_receive_expect entering: type 107 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 106 debug3: mm_answer_pam_query debug3: PAM: sshpam_query entering debug3: ssh_msg_recv entering debug1: do_pam_account: called debug3: PAM: do_pam_account pam_acct_mgmt = 10 (Get new authentication token) debug3: sshpam_password_change_required 1 debug3: PAM: sshpam_thread_conv entering, 1 messages debug3: ssh_msg_send: type 3 debug3: PAM: sshpam_thread_conv entering, 1 messages debug3: ssh_msg_send: type 1 debug3: ssh_msg_recv entering debug3: ssh_msg_recv entering debug3: mm_request_send entering: type 107 debug3: mm_sshpam_query: pam_query returned 0 [preauth] Postponed keyboard-interactive/pam for test from 139.25.181.1 port 55087 ssh2 [preauth] debug3: mm_sshpam_respond [preauth] debug3: mm_request_send entering: type 108 [preauth] debug3: mm_sshpam_respond: waiting for MONITOR_ANS_PAM_RESPOND [preauth] debug3: mm_request_receive_expect entering: type 109 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 108 debug3: mm_answer_pam_respond debug2: PAM: sshpam_respond entering, 1 responses debug3: ssh_msg_send: type 6 debug3: mm_request_send entering: type 109 debug3: mm_sshpam_respond: pam_respond returned 1 [preauth] debug3: mm_sshpam_query [preauth] debug3: mm_request_send entering: type 106 [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 106 debug3: mm_answer_pam_query debug3: PAM: sshpam_query entering debug3: ssh_msg_recv entering debug3: PAM: sshpam_thread_conv entering, 1 messages debug3: ssh_msg_send: type 1 debug3: ssh_msg_recv entering debug3: mm_request_send entering: type 107 debug3: mm_sshpam_query: waiting for MONITOR_ANS_PAM_QUERY [preauth] debug3: mm_request_receive_expect entering: type 107 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_sshpam_query: pam_query returned 0 [preauth] Postponed keyboard-interactive/pam for test from 139.25.181.1 port 55087 ssh2 [preauth] debug3: mm_sshpam_respond [preauth] debug3: mm_request_send entering: type 108 [preauth] debug3: mm_sshpam_respond: waiting for MONITOR_ANS_PAM_RESPOND [preauth] debug3: mm_request_receive_expect entering: type 109 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 108 debug3: mm_answer_pam_respond debug2: PAM: sshpam_respond entering, 1 responses debug3: ssh_msg_send: type 6 debug3: mm_request_send entering: type 109 debug3: mm_sshpam_respond: pam_respond returned 1 [preauth] debug3: mm_sshpam_query [preauth] debug3: mm_request_send entering: type 106 [preauth] debug3: mm_sshpam_query: waiting for MONITOR_ANS_PAM_QUERY [preauth] debug3: mm_request_receive_expect entering: type 107 [preauth] debug3: mm_request_receive entering [preauth] debug3: mm_request_receive entering debug3: monitor_read: checking request 106 debug3: mm_answer_pam_query debug3: PAM: sshpam_query entering debug3: ssh_msg_recv entering mm_log_handler: write: Broken pipe debug1: do_cleanup debug3: PAM: sshpam_thread_cleanup entering Regards Van Cu Truong AIS GER MS GF ICS TOL EP1 Tel.: +49 (211) 399 33598 Mobile: +49 (163) 1651728 cu.truongl at atos.net Otto-Hahn-Ring 6 81739 M?nchen, Deutschland de.atos.net [https://careers.atos.net/fe/images/client/Atos01/v1/css/logo.gif] From azet at azet.org Wed Nov 6 00:17:27 2013 From: azet at azet.org (Aaron Zauner) Date: Tue, 5 Nov 2013 14:17:27 +0100 Subject: ssh-keygen DSA keylenght limit In-Reply-To: <20131105112339.GA15586@gate.dtucker.net> References: <20131105112339.GA15586@gate.dtucker.net> Message-ID: Hi Darren, I?ve read through the IETF and bugzilla threads. Thats pretty unfortunate. I?ll probably just disable DSA host keys or switch to ECDSA. Thanks for the additional information, Aaron On 05 Nov 2013, at 12:23, Darren Tucker wrote: > On Tue, Nov 05, 2013 at 11:57:04AM +0100, Aaron Zauner wrote: >> I am wondering as to why there is a 1024 bit limitation in the >> `ssh-keygen` tool up until the current CVS version. > [...] > > It's deliberate. RFC4253 requires the use of SHA1 for DSA keys and > FIPS-186-3 requires the use of a longer hash than SHA1 for keys larger > than 1024 bits. The only way to comply with both is to allow only > keys that are 1024 bits. > > See https://bugzilla.mindrot.org/show_bug.cgi?id=1647 for further info. > > -- > Darren Tucker (dtucker at zip.com.au) > GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 > Good judgement comes with experience. Unfortunately, the experience > usually comes from bad judgement. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 1091 bytes Desc: Message signed with OpenPGP using GPGMail URL: From aris at 0xbadc0de.be Wed Nov 6 01:25:15 2013 From: aris at 0xbadc0de.be (Aris Adamantiadis) Date: Tue, 05 Nov 2013 15:25:15 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> Message-ID: <5278FFCB.7080809@0xbadc0de.be> Hi, For my part I chose Curve25519 because it's there since a while and had time to be studied. The other curves you mention have all been introduced in 2013. I don't know enough mathematics to criticize any of these curves, but letting some times for others to do so seems prudent. Aris Le 4/11/13 21:40, mancha a ?crit : > Curve2213, Curve1174, Curve383187, and Curve3617 From mancha1 at hush.com Wed Nov 6 06:40:23 2013 From: mancha1 at hush.com (mancha) Date: Tue, 5 Nov 2013 19:40:23 +0000 (UTC) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal References: <5241F449.8070407@0xbadc0de.be> <5278FFCB.7080809@0xbadc0de.be> Message-ID: Aris Adamantiadis 0xbadc0de.be> writes: > Hi, > > For my part I chose Curve25519 because it's there since a while and had > time to be studied. The other curves you mention have all been > introduced in 2013. I don't know enough mathematics to criticize any of > these curves, but letting some times for others to do so seems prudent. Aris: Thank you for your reply. Let me follow-up my post to make sure I am not misunderstood. Given questionable explanations/rationale surrounding constant selection in some NIST curves, there is genuine justification for considering alternatives. I thank you for your valuable contribution with this and thank the OpenSSH developers for embracing it. Dr. Bernstein's track record is quite impressive and like you I share the belief that generally in cryptography "older is better". More specifically, Curve25519 is impervious to Pohlig-Hellman and twist attacks. Also, we ensure primes are large enough to mitigate attacks such as Pollard's rho, Shank's, etc. As far as implementation, NaCl's certainly appears quite crisp (https://twitter.com/tweetnacl). That said, a key lesson from the NIST curve controversy is the importance of retaining a healthy dose of skepticism. And I do. Finally, there's a high value to the OpenSSH community in expanding options available (kexalg, mac, cipher, etc.) so let me express my hope for continued vigorous activity in this area. Many thanks. --mancha From djm at mindrot.org Wed Nov 6 09:14:54 2013 From: djm at mindrot.org (Damien Miller) Date: Wed, 6 Nov 2013 09:14:54 +1100 (EST) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> <5278FFCB.7080809@0xbadc0de.be> Message-ID: On Tue, 5 Nov 2013, mancha wrote: > Finally, there's a high value to the OpenSSH community in expanding > options available (kexalg, mac, cipher, etc.) so let me express my > hope for continued vigorous activity in this area. There's also cost. Each new algorithm we add increases attack surface and maintenance cost. We don't want to add things just because they are available, they have to offer something that the current set of options don't. At the moment, we're only looking at adding ed25519 as a public-key algorithm and chacha20+poly1305 as an AEAD similar to Adam Langley's proposal for TLS: http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-01 -d From nicolai-openssh at chocolatine.org Thu Nov 7 09:33:48 2013 From: nicolai-openssh at chocolatine.org (Nicolai) Date: Wed, 6 Nov 2013 16:33:48 -0600 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <5278FFCB.7080809@0xbadc0de.be> References: <5241F449.8070407@0xbadc0de.be> <5278FFCB.7080809@0xbadc0de.be> Message-ID: <20131106223348.GA13851@vectra.student.iastate.edu> On Tue, Nov 05, 2013 at 03:25:15PM +0100, Aris Adamantiadis wrote: > Hi, > > For my part I chose Curve25519 because it's there since a while and had > time to be studied. The other curves you mention have all been > introduced in 2013. Additional good reasons are that Curve25519 is used elsewhere in real things: DNSCurve, Tor (newer versions), DNSCrypt, ZeroMQ. Curve25519 is also in CurveCP, MinimaLT, and will be added to Google's new QUIC protocol. Big thanks to Aris for this! Nicolai From mancha1 at hush.com Thu Nov 7 10:28:31 2013 From: mancha1 at hush.com (mancha) Date: Wed, 6 Nov 2013 23:28:31 +0000 (UTC) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal References: <5241F449.8070407@0xbadc0de.be> <5278FFCB.7080809@0xbadc0de.be> Message-ID: Damien Miller mindrot.org> writes: > We don't want to add things just because they are available, they have > to offer something that the current set of options don't. I can see how my comment could be misinterpreted but I'm certainly not suggesting that. What I tried to say (awkwardly) is that in the current context there's value in continually re-visiting assumptions and a role for risk-reducing diversification that, if warranted, expands options beyond the bounds of controversial standards-driven suites. > At the moment, we're only looking at adding ed25519 as a public-key > algorithm and chacha20+poly1305 as an AEAD similar to Adam Langley's > proposal for TLS That sounds like a great complement to aes{128,256}-gcm at openssh.com. Have you been tracking his progress so far? e.g.: http://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=9a8646510b PS I was very anxious to test Curve25519 so I ported Markus' recent commits to 6.3p1. For those running portable who are interested in giving this a whirl, I've posted here: http://sf.net/projects/mancha/files/misc/openssh-6.3p1-curve25519.diff Cheers. --mancha From aris at 0xbadc0de.be Thu Nov 7 20:30:23 2013 From: aris at 0xbadc0de.be (Aris Adamantiadis) Date: Thu, 07 Nov 2013 10:30:23 +0100 Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: References: <5241F449.8070407@0xbadc0de.be> <5278FFCB.7080809@0xbadc0de.be> Message-ID: <527B5DAF.50106@0xbadc0de.be> Le 7/11/13 00:28, mancha a ?crit : > > That sounds like a great complement to aes{128,256}-gcm at openssh.com. > Have you been tracking his progress so far? e.g.: > http://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=9a8646510b I am not very comfortable with aes*-gcm at openssh.com because the packet len is not encrypted under the claim that it is not possible to do both encryption and authentication on the length field. I believe that's not true, a competing authenticated encryption mechanism should fix this (e.g. by sending an authentication token on both every encrypted length and packet payload). This unencrypted length thing brings SSH2 back to the SSH1 days where it was trivial to sniff the length of a password. Contrary to what the RFC tells, sending ignore packets doesn't help. Aris From ernstk at us.ibm.com Fri Nov 8 02:48:59 2013 From: ernstk at us.ibm.com (Ernst Kratschmer) Date: Thu, 7 Nov 2013 10:48:59 -0500 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server Message-ID: Dear openssh developer, I want to use a Win7 client with putty to access a Linux host running an openssh 6.2p2 through a VPN connection. These connection worked relatively flawless with all versions of openssh up until openssh 6.1p1. Since the openssh 6.2p2 upgrade the ssh connection fail consistently with a message: Network error, connection reset by peer. After inspecting the tcp transmission between the putty client and openssh server it appears that the maximum MTU limit of 1362 of the VPN connection, causes the server to break the 1460 byte cipher string into two packets. At that point the ssh client, putty or openssh, resets the connection. This was not a problem with openssh 6.1p1 since the cipher string was only 1106 bytes and therefore transmitted in one packet. Since I am stuck with the VPN MTU limit of 1362, I am hoping that you could help in some form to get the ssh connection working again by, e.g., limit the cipher string to less than 1322 bytes? Thanks in advance for any help you can provide to fix this problem, Ernst Kratschmer From vincenzo.romano at notorand.it Fri Nov 8 04:09:43 2013 From: vincenzo.romano at notorand.it (Vincenzo Romano) Date: Thu, 7 Nov 2013 18:09:43 +0100 Subject: Question about ClientAliveCountMax Message-ID: Hi all. What is the expected/intended semantics of setting ClientAliveCountMax to 0 and ClientAliveInterval to non-zero? Thanks in advance From jan.pechanec at oracle.com Fri Nov 8 05:05:14 2013 From: jan.pechanec at oracle.com (Jan Pechanec) Date: Thu, 7 Nov 2013 10:05:14 -0800 (PST) Subject: Question about ClientAliveCountMax In-Reply-To: References: Message-ID: On Thu, 7 Nov 2013, Vincenzo Romano wrote: >Hi all. >What is the expected/intended semantics of setting ClientAliveCountMax >to 0 and ClientAliveInterval to non-zero? I believe it should work as an idle timeout from the server side to disconnect idle clients. J. -- Jan Pechanec From vincenzo.romano at notorand.it Fri Nov 8 05:14:05 2013 From: vincenzo.romano at notorand.it (Vincenzo Romano) Date: Thu, 7 Nov 2013 19:14:05 +0100 Subject: Question about ClientAliveCountMax In-Reply-To: References: Message-ID: 2013/11/7 Jan Pechanec : > On Thu, 7 Nov 2013, Vincenzo Romano wrote: > >>Hi all. >>What is the expected/intended semantics of setting ClientAliveCountMax >>to 0 and ClientAliveInterval to non-zero? > > I believe it should work as an idle timeout from the server side > to disconnect idle clients. J. I think you misunderstood me. ClientAliveCountMax is a counter. ClientAliveInterval is a timeout interval. From jan.pechanec at oracle.com Fri Nov 8 05:28:11 2013 From: jan.pechanec at oracle.com (Jan Pechanec) Date: Thu, 7 Nov 2013 10:28:11 -0800 (PST) Subject: Question about ClientAliveCountMax In-Reply-To: References: Message-ID: On Thu, 7 Nov 2013, Vincenzo Romano wrote: >2013/11/7 Jan Pechanec : >> On Thu, 7 Nov 2013, Vincenzo Romano wrote: >> >>>Hi all. >>>What is the expected/intended semantics of setting ClientAliveCountMax >>>to 0 and ClientAliveInterval to non-zero? >> >> I believe it should work as an idle timeout from the server side >> to disconnect idle clients. J. > >I think you misunderstood me. I didn't, you asked what would happen and I told you. I take it you haven't try that. /* timeout, check to see how many we have had */ if (packet_inc_alive_timeouts() > options.client_alive_count_max) { logit("Timeout, client not responding."); cleanup_exit(255); } >ClientAliveCountMax is a counter. ClientAliveInterval is a timeout interval. -- Jan Pechanec From vincenzo.romano at notorand.it Fri Nov 8 07:03:59 2013 From: vincenzo.romano at notorand.it (Vincenzo Romano) Date: Thu, 7 Nov 2013 21:03:59 +0100 Subject: Question about ClientAliveCountMax In-Reply-To: References: Message-ID: 2013/11/7 Jan Pechanec : > On Thu, 7 Nov 2013, Vincenzo Romano wrote: > >>2013/11/7 Jan Pechanec : >>> On Thu, 7 Nov 2013, Vincenzo Romano wrote: >>> >>>>Hi all. >>>>What is the expected/intended semantics of setting ClientAliveCountMax >>>>to 0 and ClientAliveInterval to non-zero? >>> >>> I believe it should work as an idle timeout from the server side >>> to disconnect idle clients. J. >> >>I think you misunderstood me. > > I didn't, you asked what would happen and I told you. I take it > you haven't try that. > > /* timeout, check to see how many we have had */ > if (packet_inc_alive_timeouts() > options.client_alive_count_max) { > logit("Timeout, client not responding."); > cleanup_exit(255); > } > >>ClientAliveCountMax is a counter. ClientAliveInterval is a timeout interval. With ClientAliveCountMax == 0 there will be no "client alive packet" sent and I will force a disconnection if there is no traffic within ClientAliveInterval secs. With ClientAliveCountMax == 1 there will be 1 "client alive packet" sent and I will force a disconnection if there is no traffic and no reply within 2*ClientAliveInterval secs. Is this correct? Sorry for asking silly questions and abusing your patience! From jan.pechanec at oracle.com Fri Nov 8 07:38:12 2013 From: jan.pechanec at oracle.com (Jan Pechanec) Date: Thu, 7 Nov 2013 12:38:12 -0800 (PST) Subject: Question about ClientAliveCountMax In-Reply-To: References: Message-ID: On Thu, 7 Nov 2013, Vincenzo Romano wrote: >>>>>Hi all. >>>>>What is the expected/intended semantics of setting ClientAliveCountMax >>>>>to 0 and ClientAliveInterval to non-zero? >>>> >>>> I believe it should work as an idle timeout from the server side >>>> to disconnect idle clients. J. >>> >>>I think you misunderstood me. >> >> I didn't, you asked what would happen and I told you. I take it >> you haven't try that. >> >> /* timeout, check to see how many we have had */ >> if (packet_inc_alive_timeouts() > options.client_alive_count_max) { >> logit("Timeout, client not responding."); >> cleanup_exit(255); >> } >> >>>ClientAliveCountMax is a counter. ClientAliveInterval is a timeout interval. > >With ClientAliveCountMax == 0 there will be no "client alive packet" >sent and I will force a disconnection if there is no traffic within >ClientAliveInterval secs. yes, that's how I remember it and that's why it can be "overloaded" and used to disconnect idle clients since nothing is actually sent from the server. >With ClientAliveCountMax == 1 there will be 1 "client alive packet" >sent and I will force a disconnection if there is no traffic and no >reply within 2*ClientAliveInterval secs. yes, I believe that is correct. You can easily verify that if you set up a firewall, for example. cheers, J. > >Is this correct? >Sorry for asking silly questions and abusing your patience! >_______________________________________________ >openssh-unix-dev mailing list >openssh-unix-dev at mindrot.org >https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev > -- Jan Pechanec From os at ohmu.fi Fri Nov 8 07:48:29 2013 From: os at ohmu.fi (Oskari Saarenmaa) Date: Thu, 07 Nov 2013 22:48:29 +0200 Subject: [PATCH] hostfile: list known names (if any) for new hostkeys In-Reply-To: <20121227151506.GA29988@timantti.taisia.fi> References: <20121227151506.GA29988@timantti.taisia.fi> Message-ID: <527BFC9D.2050200@ohmu.fi> 27.12.2012 17:15, Oskari Saarenmaa kirjoitti: > When connecting to a host for which there's no known hostkey, check if the > relevant key has been accepted for other hostnames. This is useful when > connecting to a host with a dymamic IP address or multiple names. Ping, anyone had a chance to look at this patch yet? I've also attached it to bugzilla, https://bugzilla.mindrot.org/show_bug.cgi?id=2131 Thanks, Oskari From kurt.w.heberlein at hp.com Fri Nov 8 08:09:50 2013 From: kurt.w.heberlein at hp.com (Heberlein, Kurt William) Date: Thu, 7 Nov 2013 21:09:50 +0000 Subject: [PATCH] hostfile: list known names (if any) for new hostkeys In-Reply-To: <527BFC9D.2050200@ohmu.fi> References: <20121227151506.GA29988@timantti.taisia.fi> <527BFC9D.2050200@ohmu.fi> Message-ID: <304F70D12CDFEB43BB9DFB8144B443A923558EF5@G6W2478.americas.hpqcorp.net> Doesn't this play in the same space as StrictHostKeyChecking ? Doesn't it also sort of expose MITM if a known hostkey arrives from a different IP/named host? Cheers, -Kurt -----Original Message----- From: openssh-unix-dev-bounces+kurt.w.heberlein=hp.com at mindrot.org [mailto:openssh-unix-dev-bounces+kurt.w.heberlein=hp.com at mindrot.org] On Behalf Of Oskari Saarenmaa Sent: Thursday, November 07, 2013 2:48 PM To: openssh-unix-dev at mindrot.org Subject: Re: [PATCH] hostfile: list known names (if any) for new hostkeys 27.12.2012 17:15, Oskari Saarenmaa kirjoitti: > When connecting to a host for which there's no known hostkey, check if the > relevant key has been accepted for other hostnames. This is useful when > connecting to a host with a dymamic IP address or multiple names. Ping, anyone had a chance to look at this patch yet? I've also attached it to bugzilla, https://bugzilla.mindrot.org/show_bug.cgi?id=2131 Thanks, Oskari _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev at mindrot.org https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev From os at ohmu.fi Fri Nov 8 08:49:20 2013 From: os at ohmu.fi (Oskari Saarenmaa) Date: Thu, 7 Nov 2013 23:49:20 +0200 Subject: [PATCH] hostfile: list known names (if any) for new hostkeys In-Reply-To: <304F70D12CDFEB43BB9DFB8144B443A923558EF5@G6W2478.americas.hpqcorp.net> References: <20121227151506.GA29988@timantti.taisia.fi> <527BFC9D.2050200@ohmu.fi> <304F70D12CDFEB43BB9DFB8144B443A923558EF5@G6W2478.americas.hpqcorp.net> Message-ID: <20131107214920.GA31576@saarenmaa.fi> On Thu, Nov 07, 2013 at 09:09:50PM +0000, Heberlein, Kurt William wrote: > Doesn't this play in the same space as StrictHostKeyChecking ? Doesn't > it also sort of expose MITM if a known hostkey arrives from a different > IP/named host? This is related, but different. This patch matches hostkeys for new hosts against hostkeys of already known hosts but doesn't accept or reject them, it just prints out the matching, already known keys. I don't think there's much chance for MITM, the only thing this patch does is listing all previously accepted keys that match the new key presented by the remote host. The idea is to make it easier for the user to verify that the new host (new hostname or ip address) they're connecting to is the same host they've already accessed previously, if two hosts share the same key the chances are that the administrator has knowingly installed the same key on multiple hosts (or they've been compromised, or they're running Debian's broken OpenSSL). This patch would've probably exposed the issues in Debian's key generation a bit sooner as a number of unrelated hosts would've been found to use identical keys. > -----Original Message----- > 27.12.2012 17:15, Oskari Saarenmaa kirjoitti: > > When connecting to a host for which there's no known hostkey, check if the > > relevant key has been accepted for other hostnames. This is useful when > > connecting to a host with a dymamic IP address or multiple names. > > Ping, anyone had a chance to look at this patch yet? I've also attached > it to bugzilla, > https://bugzilla.mindrot.org/show_bug.cgi?id=2131 / Oskari From djm at mindrot.org Fri Nov 8 13:54:16 2013 From: djm at mindrot.org (Damien Miller) Date: Fri, 8 Nov 2013 13:54:16 +1100 (EST) Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: Message-ID: On Thu, 7 Nov 2013, Ernst Kratschmer wrote: > Dear openssh developer, > > I want to use a Win7 client with putty to access a Linux host running an > openssh 6.2p2 through a VPN connection. These connection worked relatively > flawless with all versions of openssh up until openssh 6.1p1. Since the > openssh 6.2p2 upgrade the ssh connection fail consistently with a message: > Network error, connection reset by peer. After inspecting the tcp > transmission between the putty client and openssh server it appears that > the maximum MTU limit of 1362 of the VPN connection, causes the server to > break the 1460 byte cipher string into two packets. At that point the ssh > client, putty or openssh, resets the connection. > > This was not a problem with openssh 6.1p1 since the cipher string was only > 1106 bytes and therefore transmitted in one packet. Since I am stuck with > the VPN MTU limit of 1362, I am hoping that you could help in some form to > get the ssh connection working again by, e.g., limit the cipher string to > less than 1322 bytes? I don't think this is something we can fix in OpenSSH. You could work around it by shrinking the list of ciphers/MACs/key exchange algorithms that are offered using sshd_config's "Ciphers", "MACs" and "KexAlgorithms" options. -d From djm at cvs.openbsd.org Fri Nov 8 14:32:35 2013 From: djm at cvs.openbsd.org (Damien Miller) Date: Thu, 7 Nov 2013 20:32:35 -0700 (MST) Subject: Announce: OpenSSH 6.4 released Message-ID: <201311080332.rA83WZLW023065@cvs.openbsd.org> Changes since OpenSSH 6.3 ========================= This release fixes a security bug: * sshd(8): fix a memory corruption problem triggered during rekeying when an AES-GCM cipher is selected. Full details of the vulnerability are available at: http://www.openssh.com/txt/gcmrekey.adv Checksums: ========== - SHA1 (openssh-6.4.tar.gz) = 4caf1a50eb3a3da821c16298c4aaa576fe24210c - SHA1 (openssh-6.4p1.tar.gz) = cf5fe0eb118d7e4f9296fbc5d6884965885fc55d Reporting Bugs: =============== - Please read http://www.openssh.com/report.html Security bugs should be reported directly to openssh at openssh.com OpenSSH is brought to you by Markus Friedl, Niels Provos, Theo de Raadt, Kevin Steves, Damien Miller, Darren Tucker, Jason McIntyre, Tim Rice and Ben Lindstrom. From flavien-ssh at lebarbe.net Fri Nov 8 21:52:11 2013 From: flavien-ssh at lebarbe.net (Flavien Lebarbe) Date: Fri, 8 Nov 2013 11:52:11 +0100 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: Message-ID: <20131108105210.GA5836@srv3.flavien.org> > On Thu, 7 Nov 2013, Ernst Kratschmer wrote: > > > Dear openssh developer, > > > > I want to use a Win7 client with putty to access a Linux host running an > > openssh 6.2p2 through a VPN connection. These connection worked relatively > > flawless with all versions of openssh up until openssh 6.1p1. Since the > > openssh 6.2p2 upgrade the ssh connection fail consistently with a message: > > Network error, connection reset by peer. After inspecting the tcp > > transmission between the putty client and openssh server it appears that > > the maximum MTU limit of 1362 of the VPN connection, causes the server to > > break the 1460 byte cipher string into two packets. At that point the ssh > > client, putty or openssh, resets the connection. > > > > This was not a problem with openssh 6.1p1 since the cipher string was only > > 1106 bytes and therefore transmitted in one packet. Since I am stuck with > > the VPN MTU limit of 1362, I am hoping that you could help in some form to > > get the ssh connection working again by, e.g., limit the cipher string to > > less than 1322 bytes? Damien answered : > I don't think this is something we can fix in OpenSSH. I don't get it. Could you elaborate on this ? Please correct me if I'm wrong, but from my point of view, TCP splitting packets to respect MTU somewhere in transit should not have any impact at the functionnal level. We should not expect the values returned by read()/recv() to match those we gave to write()/send(). When read()-ing on a socket, the size returned is at the kernel (or libc) discretion. If it prefers to send us the data byte by byte, it is allowed to, and the process is supposed to wait for more data if it expects more. I'm not telling it's easy to implement in OpenSSH as I never seriously looked at the code but saying it cannot be done surprises me. Thanks for your clues ! Flavien. From dtucker at zip.com.au Fri Nov 8 22:48:57 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Fri, 8 Nov 2013 22:48:57 +1100 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: <20131108105210.GA5836@srv3.flavien.org> References: <20131108105210.GA5836@srv3.flavien.org> Message-ID: <20131108114857.GA7922@gate.dtucker.net> On Fri, Nov 08, 2013 at 11:52:11AM +0100, Flavien Lebarbe wrote: > > On Thu, 7 Nov 2013, Ernst Kratschmer wrote: [vpn + mtu problem] > Damien answered : > > I don't think this is something we can fix in OpenSSH. > > I don't get it. Could you elaborate on this ? > > Please correct me if I'm wrong, but from my point of view, TCP > splitting packets to respect MTU somewhere in transit should not have > any impact at the functionnal level. We should not expect the values > returned by read()/recv() to match those we gave to write()/send(). it doesn't. it does expect that they make it to the other end, though, which doesn't seem to happen in this case. > When read()-ing on a socket, the size returned is at the kernel (or > libc) discretion. If it prefers to send us the data byte by byte, it > is allowed to, and the process is supposed to wait for more data if > it expects more. > > I'm not telling it's easy to implement in OpenSSH as I never seriously > looked at the code but saying it cannot be done surprises me. TCP is supposed to be a bi-directional reliable byte stream and the ssh protocol doesn't rely on it being anything more than that. The network in this case seems broken. It sounds like the classic "MTU causes IP fragmentation then something else drops the fragments" problem. Often something doing this will also reduce the TCP MSS so that the endpoints don't emit IP packets big enough to fragment, but it seems not in this case. It can be worked around in the config as described by Damien but any attempt to work around it in openssh would be an ugly hack at best and would likely hurt performace on networks that aren't broken. -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From vinschen at redhat.com Fri Nov 8 23:59:57 2013 From: vinschen at redhat.com (Corinna Vinschen) Date: Fri, 8 Nov 2013 13:59:57 +0100 Subject: [patch/Cygwin]: Simplify host key generation in ssh-host-config script In-Reply-To: <20130805120127.GO23060@calimero.vinschen.de> References: <20130805120127.GO23060@calimero.vinschen.de> Message-ID: <20131108125957.GD16306@calimero.vinschen.de> Ping? I sent this patch 5 weeks before 6.3 has been announced and it's still not in 6.4, unfortunately. Any chance this could be applied soon? Thanks, Corinna On Aug 5 14:01, Corinna Vinschen wrote: > Hi, > > as the subject says, the below patch just simplifies the host > key generation in the Cygwin-specific ssh-host-config script. > Rather than testing and generating each key, call ssh-keygen -A. > > Could somebody with checkin rights please apply? > > > Thanks, > Corinna > > > Index: contrib/cygwin/ssh-host-config > =================================================================== > RCS file: /cvs/openssh/contrib/cygwin/ssh-host-config,v > retrieving revision 1.33 > diff -u -p -r1.33 ssh-host-config > --- contrib/cygwin/ssh-host-config 2 Jul 2013 10:06:47 -0000 1.33 > +++ contrib/cygwin/ssh-host-config 5 Aug 2013 12:00:39 -0000 > @@ -68,54 +68,6 @@ password_value= > opt_force=no > > # ====================================================================== > -# Routine: create_host_keys > -# ====================================================================== > -create_host_keys() { > - local ret=0 > - > - if [ ! -f "${SYSCONFDIR}/ssh_host_key" ] > - then > - csih_inform "Generating ${SYSCONFDIR}/ssh_host_key" > - if ! /usr/bin/ssh-keygen -t rsa1 -f ${SYSCONFDIR}/ssh_host_key -N '' > /dev/null > - then > - csih_warning "Generating ${SYSCONFDIR}/ssh_host_key failed!" > - let ++ret > - fi > - fi > - > - if [ ! -f "${SYSCONFDIR}/ssh_host_rsa_key" ] > - then > - csih_inform "Generating ${SYSCONFDIR}/ssh_host_rsa_key" > - if ! /usr/bin/ssh-keygen -t rsa -f ${SYSCONFDIR}/ssh_host_rsa_key -N '' > /dev/null > - then > - csih_warning "Generating ${SYSCONFDIR}/ssh_host_key failed!" > - let ++ret > - fi > - fi > - > - if [ ! -f "${SYSCONFDIR}/ssh_host_dsa_key" ] > - then > - csih_inform "Generating ${SYSCONFDIR}/ssh_host_dsa_key" > - if ! /usr/bin/ssh-keygen -t dsa -f ${SYSCONFDIR}/ssh_host_dsa_key -N '' > /dev/null > - then > - csih_warning "Generating ${SYSCONFDIR}/ssh_host_key failed!" > - let ++ret > - fi > - fi > - > - if [ ! -f "${SYSCONFDIR}/ssh_host_ecdsa_key" ] > - then > - csih_inform "Generating ${SYSCONFDIR}/ssh_host_ecdsa_key" > - if ! /usr/bin/ssh-keygen -t ecdsa -f ${SYSCONFDIR}/ssh_host_ecdsa_key -N '' > /dev/null > - then > - csih_warning "Generating ${SYSCONFDIR}/ssh_host_key failed!" > - let ++ret > - fi > - fi > - return $ret > -} # --- End of create_host_keys --- # > - > -# ====================================================================== > # Routine: update_services_file > # ====================================================================== > update_services_file() { > @@ -719,8 +671,8 @@ then > let ++warning_cnt > fi > > -# host keys > -create_host_keys || let warning_cnt+=$? > +# generate missing host keys > +/usr/bin/ssh-keygen -A || let warning_cnt+=$? > > # handle ssh_config > csih_install_config "${SYSCONFDIR}/ssh_config" "${SYSCONFDIR}/defaults" || let ++warning_cnt > > > -- > Corinna Vinschen > Cygwin Maintainer > Red Hat > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- Corinna Vinschen Cygwin Maintainer Red Hat -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: not available URL: From dtucker at zip.com.au Sat Nov 9 00:23:46 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Sat, 9 Nov 2013 00:23:46 +1100 Subject: [patch/Cygwin]: Simplify host key generation in ssh-host-config script In-Reply-To: <20131108125957.GD16306@calimero.vinschen.de> References: <20130805120127.GO23060@calimero.vinschen.de> <20131108125957.GD16306@calimero.vinschen.de> Message-ID: <20131108132346.GA5805@gate.dtucker.net> On Fri, Nov 08, 2013 at 01:59:57PM +0100, Corinna Vinschen wrote: > Ping? Sorry, this dropped off my radar. Applied, thanks. > I sent this patch 5 weeks before 6.3 has been announced and it's still > not in 6.4, unfortunately. Any chance this could be applied soon? 6.4p1 is a bit unusual in that it's branched directly from 6.3p1 and there's no portable changes in it (even the things already applied to HEAD since 6.3p1). -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From vinschen at redhat.com Sat Nov 9 00:42:50 2013 From: vinschen at redhat.com (Corinna Vinschen) Date: Fri, 8 Nov 2013 14:42:50 +0100 Subject: [patch/Cygwin]: Simplify host key generation in ssh-host-config script In-Reply-To: <20131108132346.GA5805@gate.dtucker.net> References: <20130805120127.GO23060@calimero.vinschen.de> <20131108125957.GD16306@calimero.vinschen.de> <20131108132346.GA5805@gate.dtucker.net> Message-ID: <20131108134250.GF16306@calimero.vinschen.de> On Nov 9 00:23, Darren Tucker wrote: > On Fri, Nov 08, 2013 at 01:59:57PM +0100, Corinna Vinschen wrote: > > Ping? > > Sorry, this dropped off my radar. Applied, thanks. Thank you, Corinna -- Corinna Vinschen Cygwin Maintainer Red Hat -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: not available URL: From ernstk at us.ibm.com Sat Nov 9 02:26:28 2013 From: ernstk at us.ibm.com (Ernst Kratschmer) Date: Fri, 8 Nov 2013 10:26:28 -0500 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: <20131108114857.GA7922@gate.dtucker.net> References: <20131108105210.GA5836@srv3.flavien.org> <20131108114857.GA7922@gate.dtucker.net> Message-ID: Hi everybody, thank you very much for your quick reply. Let me first address Damien's comment. Following some other people's "trial and errors" around the internet, I have already started to look for ways to limit the "cipher string", but did not have any success. So far, I tried using a config file in ~/.ssh/ which specified just a few Ciphers and MACs. My debug showed that it did not change the packet length, still 1460. Next I took a look at /etc/ssh/sshd_config and noticed that it did not explicitly specify any Ciphers or MACs, but ssh_config did. I then copied the few Ciphers and MACs from ssh_config to sshd_config and restarted sshd. Again, my debug showed that it did not change the packet length, still 1460. Most likely, I am doing something wrong here, but in any case I would greatly appreciate it if you could provide me with instructions how to shorten the "cipher string" length by modifying the config files. If I understand Darren correctly, he is concerned that the packet fragmentation causes fragments to get dropped. From my debug, I can see that the 1460 byte packet get split into two packets exactly as expected from the MTU limit. And both packets get sent to the client. The client then resets the communication. This happens regardless of the type of client software used, Cygwin, putty, openssh any version, etc. Therefore, I wonder if Flavien's comment is correct, or, if somehow all ssh clients expect to reveice the "cipher string" in a single packet. I admit that this is a wild speculation from someone who hasn't examined the source code. I just find it remarkable, that all ssh clients I tried show the same behavior in this case. I hope you know the answer. -Ernst From: Darren Tucker To: Damien Miller , Ernst Kratschmer/Watson/IBM at IBMUS, openssh-unix-dev at mindrot.org, Date: 11/08/2013 06:49 AM Subject: Re: VPN MTU limit breaks ssh connection to openssh 6.2p2 server On Fri, Nov 08, 2013 at 11:52:11AM +0100, Flavien Lebarbe wrote: > > On Thu, 7 Nov 2013, Ernst Kratschmer wrote: [vpn + mtu problem] > Damien answered : > > I don't think this is something we can fix in OpenSSH. > > I don't get it. Could you elaborate on this ? > > Please correct me if I'm wrong, but from my point of view, TCP > splitting packets to respect MTU somewhere in transit should not have > any impact at the functionnal level. We should not expect the values > returned by read()/recv() to match those we gave to write()/send(). it doesn't. it does expect that they make it to the other end, though, which doesn't seem to happen in this case. > When read()-ing on a socket, the size returned is at the kernel (or > libc) discretion. If it prefers to send us the data byte by byte, it > is allowed to, and the process is supposed to wait for more data if > it expects more. > > I'm not telling it's easy to implement in OpenSSH as I never seriously > looked at the code but saying it cannot be done surprises me. TCP is supposed to be a bi-directional reliable byte stream and the ssh protocol doesn't rely on it being anything more than that. The network in this case seems broken. It sounds like the classic "MTU causes IP fragmentation then something else drops the fragments" problem. Often something doing this will also reduce the TCP MSS so that the endpoints don't emit IP packets big enough to fragment, but it seems not in this case. It can be worked around in the config as described by Damien but any attempt to work around it in openssh would be an ugly hack at best and would likely hurt performace on networks that aren't broken. -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From alex at alex.org.uk Sat Nov 9 03:11:05 2013 From: alex at alex.org.uk (Alex Bligh) Date: Fri, 8 Nov 2013 16:11:05 +0000 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: <20131108105210.GA5836@srv3.flavien.org> <20131108114857.GA7922@gate.dtucker.net> Message-ID: On 8 Nov 2013, at 15:26, Ernst Kratschmer wrote: > If I understand Darren correctly, he is concerned that the packet > fragmentation causes fragments to get dropped. From my debug, I can see > that the 1460 byte packet get split into two packets exactly as expected > from the MTU limit. Run a ping with DF set across your tunnel and sweep the packet size. This should stop working at one particular packet size. Now run a ping without DF set across your tunnel and repeat. This should work for all packet sizes. I bet one particular size fails. This will be breaking pMTU discovery. -- Alex Bligh From peter at stuge.se Sat Nov 9 03:32:39 2013 From: peter at stuge.se (Peter Stuge) Date: Fri, 8 Nov 2013 17:32:39 +0100 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: <20131108105210.GA5836@srv3.flavien.org> <20131108114857.GA7922@gate.dtucker.net> Message-ID: <20131108163239.4910.qmail@stuge.se> Ernst Kratschmer wrote: > From my debug, I can see that the 1460 byte packet get split into > two packets exactly as expected from the MTU limit. Nobody is challenging this. > And both packets get sent to the client. Nor this. But what really matters is that they are both well-formed and that they *arrive* at the client. I'm not sure you've provided information about whether that is the case. > The client then resets the communication. If either packet is malformed then that's the right thing to do. > This happens regardless of the type of client software used, > Cygwin, putty, openssh any version, etc. As you know, TCP is not implemented by the client software, but by the operating system network stack. And given an invalid packet most operating systems will do the same (right) thing. Please analyze what the client receives, if it is two packets then investigate whether they are well-formed. If they are, then look further up the layers. //Peter From ernstk at us.ibm.com Sat Nov 9 04:33:22 2013 From: ernstk at us.ibm.com (Ernst Kratschmer) Date: Fri, 8 Nov 2013 12:33:22 -0500 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: <20131108105210.GA5836@srv3.flavien.org> <20131108114857.GA7922@gate.dtucker.net> Message-ID: Hi Alex, I am sorry, but I don't know what "ping with DF set" is. I can run "ping -l size". This fails if size is greater than 1252, over VPN or LAN. Not sure if this helps. -Ernst From: Alex Bligh To: Ernst Kratschmer/Watson/IBM at IBMUS, Cc: Alex Bligh , dtucker at zip.com.au, Damien Miller , openssh-unix-dev at mindrot.org Date: 11/08/2013 11:11 AM Subject: Re: VPN MTU limit breaks ssh connection to openssh 6.2p2 server On 8 Nov 2013, at 15:26, Ernst Kratschmer wrote: > If I understand Darren correctly, he is concerned that the packet > fragmentation causes fragments to get dropped. From my debug, I can see > that the 1460 byte packet get split into two packets exactly as expected > from the MTU limit. Run a ping with DF set across your tunnel and sweep the packet size. This should stop working at one particular packet size. Now run a ping without DF set across your tunnel and repeat. This should work for all packet sizes. I bet one particular size fails. This will be breaking pMTU discovery. -- Alex Bligh From lists at eitanadler.com Sat Nov 9 04:52:52 2013 From: lists at eitanadler.com (Eitan Adler) Date: Fri, 8 Nov 2013 12:52:52 -0500 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: <20131108105210.GA5836@srv3.flavien.org> <20131108114857.GA7922@gate.dtucker.net> Message-ID: On Fri, Nov 8, 2013 at 12:33 PM, Ernst Kratschmer wrote: > Hi Alex, [ top posting makes it difficult to follow ] > I am sorry, but I don't know what "ping with DF set" is. DF is the "Don't Fragment" bit > I can run "ping -l size". This fails if size is greater than 1252, over > VPN or LAN. -l is not useful here. You may want to use -g and -G. By default the DF bit is not set. You may use the -D flag to set it. > Not sure if this helps. -- Eitan Adler From peter at stuge.se Sat Nov 9 05:03:07 2013 From: peter at stuge.se (Peter Stuge) Date: Fri, 8 Nov 2013 19:03:07 +0100 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: <20131108105210.GA5836@srv3.flavien.org> <20131108114857.GA7922@gate.dtucker.net> Message-ID: <20131108180307.11488.qmail@stuge.se> Ernst Kratschmer wrote: > I am sorry, but I don't know what "ping with DF set" is. > I can run "ping -l size". This fails if size is greater than 1252, over > VPN or LAN. > Not sure if this helps. On Linux: $ man ping | grep -A 1 -B 5 DF -M pmtudisc_opt Select Path MTU Discovery strategy. pmtudisc_option may be either do (prohibit fragmentation, even local one), want (do PMTU discovery, fragment locally when packet size is large), or dont (do not set DF flag). $ //Peter From ernstk at us.ibm.com Sat Nov 9 08:21:16 2013 From: ernstk at us.ibm.com (Ernst Kratschmer) Date: Fri, 8 Nov 2013 16:21:16 -0500 Subject: VPN MTU limit breaks ssh connection to openssh 6.2p2 server In-Reply-To: References: <20131108105210.GA5836@srv3.flavien.org> <20131108114857.GA7922@gate.dtucker.net> Message-ID: Hi Eitan et al., at the moment I only have Fedora 18 / 19 servers and a Win7 client behind the firewall connecting via VPN available for testing. Neither system accepts a "ping -DF" command. From the Win7 client I can do a "ping -l size" (-l size Send buffer size.) or "ping -f -l size" (-f Set Don't Fragment flag in packet (IPv4-only).). In either case the maximum number of bytes I can pack into the ping request is 1252. This 1252 byte limit is the same for sending the ping request over VPN or over the LAN (I lost you as far as the purpose of this test is concerned). I did some additional testing and noticed the following. With openssh 6.1p1 the "cipher string" gets broken up into two packet which add up to exactly 840 bytes (same as the single packet at large MTU) when I set the server to a smaller MTU size of e.g. 1200 (<<1362 VPN limit). With openssh 6.2p2 the "cipher string" gets broken up into two packet which add up to 1464 bytes, which is different from 1460 bytes of the single packet at large MTU, when I set a server MTU size of e.g. 1200. This 4 byte difference only happens with openssh 6.2p2, when the "cipher string" gets split into two packets. Things get even more weird with openssh 6.2p2 and an MTU of e.g. 600. The "cipher string" gets broken up into 1160 and 384 bytes (again 4 more than the original 1460), and not into three packets as I had expected. After the 384 byte packet has been send from the server, both client and server engage in a long list of resets (R flag set). -Ernst From: Eitan Adler To: Ernst Kratschmer/Watson/IBM at IBMUS, Cc: Alex Bligh , "openssh-unix-dev at mindrot.org" , Damien Miller , Darren Tucker Date: 11/08/2013 12:53 PM Subject: Re: VPN MTU limit breaks ssh connection to openssh 6.2p2 server On Fri, Nov 8, 2013 at 12:33 PM, Ernst Kratschmer wrote: > Hi Alex, [ top posting makes it difficult to follow ] > I am sorry, but I don't know what "ping with DF set" is. DF is the "Don't Fragment" bit > I can run "ping -l size". This fails if size is greater than 1252, over > VPN or LAN. -l is not useful here. You may want to use -g and -G. By default the DF bit is not set. You may use the -D flag to set it. > Not sure if this helps. -- Eitan Adler From icantplayguitar at gmail.com Mon Nov 11 15:23:46 2013 From: icantplayguitar at gmail.com (d) Date: Sun, 10 Nov 2013 23:23:46 -0500 Subject: ssh-keygen :: PEM_write_RSA_PUBKEY failed Message-ID: I am trying to understand a change to ssh-keygen that is included with OS X Mavericks, 6.2p2 that prevents the option, -m PKCS8, from working. Previous to Mavericks I had 5.9p1 and didn't have this problem. This used to work previously- ssh-keygen -e -m PKCS8 -f $my_rsa_public_key Now it outputs- -----BEGIN PUBLIC KEY----- -----END PUBLIC KEY----- PEM_write_RSA_PUBKEY failed I think this is the change, line 296 of ssh-keygen.c, that was added in 6.1p1 that is the problem but I am not positive- 1.232 (djm 22-Apr-12): case KEY_RSA1: If I am reading the commit correctly (possibly not), it seems to state the opposite of what is intended- revision 1.232 date: 2012/04/22 01:07:31; author: djm; state: Exp; lines: +7 -5; - djm at cvs.openbsd.org 2012/02/29 11:21:26 [ssh-keygen.c] allow conversion of RSA1 keys to public PEM and PKCS8; "nice" markus@ Is this a regression or am I not on the right path? Thank you, -d From dtucker at zip.com.au Wed Nov 13 05:56:35 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Wed, 13 Nov 2013 05:56:35 +1100 Subject: Bug Report :: Tunnel (tunX) Selection, Maximum Value of 32-bit Integer Appears In Log Output Consistently In-Reply-To: <20131112050657.649912510@127.0.0.1> References: <20131112050657.649912510@127.0.0.1> Message-ID: <20131112185635.GA18034@gate.dtucker.net> On Tue, Nov 12, 2013 at 12:06:57AM -0500, SkipM wrote: > - What's "scary" is the presence of the maximum value of a 32-bit integer consistently in a line of debug log (see below) [...] > debug1: Requesting tun unit 2147483647 in mode 2 <<<---- here it is. That's a constant meaning "any tunnel device". It's defined in misc.h: $ grep SSH_TUNID_ANY misc.h #define SSH_TUNID_ANY 0x7fffffff and specified in the PROTOCOL file containing the vendor extensions implemented by OpenSSH (look for "tunnel unit number"): http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL?rev=HEAD;content-type=text/plain -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From mikep at noc.utoronto.ca Wed Nov 13 08:40:47 2013 From: mikep at noc.utoronto.ca (mikep at noc.utoronto.ca) Date: Tue, 12 Nov 2013 16:40:47 -0500 (EST) Subject: OpenSSH 6.4 connection to Cisco 6506 routers/switches fails Message-ID: Just upgraded to OpenSSH_6.4 with OpenSSL 1.0.1e and libz.so.1.2.8. Now some (but not all) Cisco router logins hang: kraken> ssh -vv -l noc XXX-mgmt.gw OpenSSH_6.4, OpenSSL 1.0.1e 11 Feb 2013 debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 50: Applying options for * debug2: ssh_connect: needpriv 0 debug1: Connecting to XXX-mgmt.gw [10.12.0.1] port 22. debug1: Connection established. debug1: could not open key file '/etc/ssh/ssh_host_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_dsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_ecdsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_rsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_dsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_ecdsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_rsa_key': Permission denied debug1: identity file /home/mikep/.ssh/id_rsa type -1 debug1: identity file /home/mikep/.ssh/id_rsa-cert type -1 debug1: identity file /home/mikep/.ssh/id_dsa type -1 debug1: identity file /home/mikep/.ssh/id_dsa-cert type -1 debug1: identity file /home/mikep/.ssh/id_ecdsa type -1 debug1: identity file /home/mikep/.ssh/id_ecdsa-cert type -1 debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_6.4 debug1: Remote protocol version 1.99, remote software version Cisco-1.25 debug1: no match: Cisco-1.25 debug2: fd 4 setting O_NONBLOCK debug2: key_type_from_name: unknown key type '2048' debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug2: kex_parse_kexinit: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 debug2: kex_parse_kexinit: ssh-rsa-cert-v01 at openssh.com,ssh-rsa-cert-v00 at openssh.com,ssh-rsa,ecdsa-sha2-nistp256-cert-v01 at openssh.com,ecdsa-sha2-nistp384-cert-v01 at openssh.com,ecdsa-sha2-nistp521-cert-v01 at openssh.com,ssh-dss-cert-v01 at openssh.com,ssh-dss-cert-v00 at openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-dss debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm at openssh.com,aes256-gcm at openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se debug2: kex_parse_kexinit: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-gcm at openssh.com,aes256-gcm at openssh.com,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: first_kex_follows 0 debug2: kex_parse_kexinit: reserved 0 debug2: kex_parse_kexinit: diffie-hellman-group1-sha1 debug2: kex_parse_kexinit: ssh-rsa debug2: kex_parse_kexinit: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc debug2: kex_parse_kexinit: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc debug2: kex_parse_kexinit: hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96 debug2: kex_parse_kexinit: hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96 debug2: kex_parse_kexinit: none debug2: kex_parse_kexinit: none debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: first_kex_follows 0 debug2: kex_parse_kexinit: reserved 0 debug2: mac_setup: found hmac-md5 debug1: kex: server->client aes128-cbc hmac-md5 none debug2: mac_setup: found hmac-md5 debug1: kex: client->server aes128-cbc hmac-md5 none debug2: dh_gen_key: priv key bits set: 129/256 debug2: bits set: 481/1024 debug1: sending SSH2_MSG_KEXDH_INIT debug1: expecting SSH2_MSG_KEXDH_REPLY [hangs] ^C Originally I had 'Cipher blowfish' set in '/etc/ssh/ssh_config', but removing that makes no difference. However, forcing '-c 3des' does allow it to work (even though '3des' is supposed to be the default): kraken> ssh -vv -c 3des -l noc XXX-mgmt.gw OpenSSH_6.4, OpenSSL 1.0.1e 11 Feb 2013 debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 50: Applying options for * debug2: ssh_connect: needpriv 0 debug1: Connecting to XXX-mgmt.gw [10.12.0.1] port 22. debug1: Connection established. debug1: could not open key file '/etc/ssh/ssh_host_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_dsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_ecdsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_rsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_dsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_ecdsa_key': Permission denied debug1: could not open key file '/etc/ssh/ssh_host_rsa_key': Permission denied debug1: identity file /home/mikep/.ssh/id_rsa type -1 debug1: identity file /home/mikep/.ssh/id_rsa-cert type -1 debug1: identity file /home/mikep/.ssh/id_dsa type -1 debug1: identity file /home/mikep/.ssh/id_dsa-cert type -1 debug1: identity file /home/mikep/.ssh/id_ecdsa type -1 debug1: identity file /home/mikep/.ssh/id_ecdsa-cert type -1 debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_6.4 debug1: Remote protocol version 1.99, remote software version Cisco-1.25 debug1: no match: Cisco-1.25 debug2: fd 4 setting O_NONBLOCK debug2: key_type_from_name: unknown key type '2048' debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug2: kex_parse_kexinit: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 debug2: kex_parse_kexinit: ssh-rsa-cert-v01 at openssh.com,ssh-rsa-cert-v00 at openssh.com,ssh-rsa,ecdsa-sha2-nistp256-cert-v01 at openssh.com,ecdsa-sha2-nistp384-cert-v01 at openssh.com,ecdsa-sha2-nistp521-cert-v01 at openssh.com,ssh-dss-cert-v01 at openssh.com,ssh-dss-cert-v00 at openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-dss debug2: kex_parse_kexinit: 3des-cbc debug2: kex_parse_kexinit: 3des-cbc debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: hmac-md5-etm at openssh.com,hmac-sha1-etm at openssh.com,umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at openssh.com,hmac-sha2-512-etm at openssh.com,hmac-ripemd160-etm at openssh.com,hmac-sha1-96-etm at openssh.com,hmac-md5-96-etm at openssh.com,hmac-md5,hmac-sha1,umac-64 at openssh.com,umac-128 at openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160 at openssh.com,hmac-sha1-96,hmac-md5-96 debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib debug2: kex_parse_kexinit: none,zlib at openssh.com,zlib debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: first_kex_follows 0 debug2: kex_parse_kexinit: reserved 0 debug2: kex_parse_kexinit: diffie-hellman-group1-sha1 debug2: kex_parse_kexinit: ssh-rsa debug2: kex_parse_kexinit: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc debug2: kex_parse_kexinit: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc debug2: kex_parse_kexinit: hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96 debug2: kex_parse_kexinit: hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96 debug2: kex_parse_kexinit: none debug2: kex_parse_kexinit: none debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: debug2: kex_parse_kexinit: first_kex_follows 0 debug2: kex_parse_kexinit: reserved 0 debug2: mac_setup: found hmac-md5 debug1: kex: server->client 3des-cbc hmac-md5 none debug2: mac_setup: found hmac-md5 debug1: kex: client->server 3des-cbc hmac-md5 none debug2: dh_gen_key: priv key bits set: 173/384 debug2: bits set: 495/1024 debug1: sending SSH2_MSG_KEXDH_INIT debug1: expecting SSH2_MSG_KEXDH_REPLY debug1: Server host key: RSA 98:1d:9c:e1:5b:20:a5:8e:95:5e:02:be:12:4b:f4:0c debug2: key_type_from_name: unknown key type '2048' debug2: key_type_from_name: unknown key type '2048' debug1: Host 'XXX-mgmt.gw' is known and matches the RSA host key. debug1: Found key in /etc/ssh/ssh_known_hosts:455 debug2: bits set: 488/1024 debug1: ssh_rsa_verify: signature correct debug2: kex_derive_keys debug2: set_newkeys: mode 1 debug1: SSH2_MSG_NEWKEYS sent debug1: expecting SSH2_MSG_NEWKEYS debug2: set_newkeys: mode 0 debug1: SSH2_MSG_NEWKEYS received debug1: Roaming not allowed by server debug1: SSH2_MSG_SERVICE_REQUEST sent debug2: service_accept: ssh-userauth debug1: SSH2_MSG_SERVICE_ACCEPT received debug2: key: /home/mikep/.ssh/id_rsa (0), debug2: key: /home/mikep/.ssh/id_dsa (0), debug2: key: /home/mikep/.ssh/id_ecdsa (0), ___ .=" "=._.---. ### ### ##### ." c ' '`p # # ## ## # # # / , `. w_/ # # # # ### # | '-. / / # # # # # # _,..._| )_-\ \_=.\ ### ## ## ### `-....-'`------)))`=-'"`'" ******************************************************************************* * This computer system is operated on behalf of the * * University of Toronto - CANADA * * * * Only authorised users are entitled to connect and/or login to this computer * * system. If you are not sure whether you are authorised, then you are not * * and should DISCONNECT IMMEDIATELY. * ******************************************************************************* debug1: Authentications that can continue: keyboard-interactive,password debug1: Next authentication method: keyboard-interactive debug2: userauth_kbdint debug2: we sent a keyboard-interactive packet, wait for reply debug2: input_userauth_info_req debug2: input_userauth_info_req: num_prompts 1 Password: '/etc/ssh/ssh_config' contents: Host * ForwardAgent yes ForwardX11 yes ForwardX11Trusted yes RhostsRSAAuthentication yes HostbasedAuthentication yes AddressFamily inet EnableSSHKeysign yes StrictHostKeyChecking ask Protocol 2 PreferredAuthentications hostbased,publickey,keyboard-interactive,password UsePrivilegedPort yes Previous version (openssh-5.9p1 with OpenSSL 1.0.1e and zlib-1.2.3) worked fine, with added 'Cipher blowfish' in the '/etc/ssh/ssh_config' file. Thanks for any hints! Mike -- Mike Peterson Information Security Analyst - Audit E-mail: mikep at noc.utoronto.ca WWW: http://www.noc.utoronto.ca/ Tel: 416-978-5230 Fax: 416-978-6620 From dtucker at zip.com.au Wed Nov 13 09:05:17 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Tue, 12 Nov 2013 17:05:17 -0500 Subject: OpenSSH 6.4 connection to Cisco 6506 routers/switches fails In-Reply-To: References: Message-ID: On Tue, Nov 12, 2013 at 4:40 PM, wrote: > Just upgraded to OpenSSH_6.4 with OpenSSL 1.0.1e and libz.so.1.2.8. > Now some (but not all) Cisco router logins hang: > > debug1: sending SSH2_MSG_KEXDH_INIT > debug1: expecting SSH2_MSG_KEXDH_REPLY > [hangs] > Suggestions in approximate order of likelihood. - the additional KexAlgorithms exceed some static buffer in the Cisco. Try: "KexAlgorithms diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1" - you have some kind of path MTU problem and the extra traffic from the additional algorithms pushes you past some packet boundary. Check the "send-q" column on client and the equivalent on the server and see if they're non-zero and non-decreasing). > Originally I had 'Cipher blowfish' set in '/etc/ssh/ssh_config', but > removing that makes no difference. That's because Cipher affects only Protocol 1 (which was some time in the past the only version at least some Cisco devices spoke). > However, forcing '-c 3des' does > allow it to work (even though '3des' is supposed to be the default): > 3des is the default Cipher Protocol 1. Protocol 2 takes a list (Ciphers) and its default is aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, aes128-gcm at openssh.com,aes256-gcm at openssh.com, aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, aes256-cbc,arcfour the -c option overrides both. -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From loganaden at gmail.com Wed Nov 13 16:44:21 2013 From: loganaden at gmail.com (Loganaden Velvindron) Date: Wed, 13 Nov 2013 09:44:21 +0400 Subject: OpenSSH 6.4 connection to Cisco 6506 routers/switches fails In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 2:05 AM, Darren Tucker wrote: > On Tue, Nov 12, 2013 at 4:40 PM, wrote: > >> Just upgraded to OpenSSH_6.4 with OpenSSL 1.0.1e and libz.so.1.2.8. >> Now some (but not all) Cisco router logins hang: >> >> debug1: sending SSH2_MSG_KEXDH_INIT >> debug1: expecting SSH2_MSG_KEXDH_REPLY >> [hangs] >> > > Suggestions in approximate order of likelihood. > - the additional KexAlgorithms exceed some static buffer in the Cisco. > Try: > "KexAlgorithms diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1" > - you have some kind of path MTU problem and the extra traffic from the > additional algorithms pushes you past some packet boundary. Check the > "send-q" column on client and the equivalent on the server and see if > they're non-zero and non-decreasing). Shouldn't Mike open a ticket at CISCO so that they start fixing the software on their side as well ? > > >> Originally I had 'Cipher blowfish' set in '/etc/ssh/ssh_config', but >> removing that makes no difference. > > > That's because Cipher affects only Protocol 1 (which was some time in the > past the only version at least some Cisco devices spoke). > > >> However, forcing '-c 3des' does >> allow it to work (even though '3des' is supposed to be the default): >> > > 3des is the default Cipher Protocol 1. Protocol 2 takes a list (Ciphers) > and its default is > > aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, > aes128-gcm at openssh.com,aes256-gcm at openssh.com, > aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, > aes256-cbc,arcfour > > the -c option overrides both. > > -- > Darren Tucker (dtucker at zip.com.au) > GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 > Good judgement comes with experience. Unfortunately, the experience > usually comes from bad judgement. > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- This message is strictly personal and the opinions expressed do not represent those of my employers, either past or present. From dtucker at zip.com.au Wed Nov 13 17:01:19 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Wed, 13 Nov 2013 01:01:19 -0500 Subject: OpenSSH 6.4 connection to Cisco 6506 routers/switches fails In-Reply-To: References: Message-ID: On Wed, Nov 13, 2013 at 12:44 AM, Loganaden Velvindron wrote: > > > Suggestions in approximate order of likelihood. > > - the additional KexAlgorithms exceed some static buffer in the Cisco. > > Try: > > "KexAlgorithms > diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1" > > - you have some kind of path MTU problem and the extra traffic from the > > additional algorithms pushes you past some packet boundary. Check the > > "send-q" column on client and the equivalent on the server and see if > > they're non-zero and non-decreasing). > > Shouldn't Mike open a ticket at CISCO so that they start fixing the > software on their side as well ? If my guesses are accurate, absolutely. Right now they're just unsubstantiated guesses, though, -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From hannes.hoerl at snowreporter.com Wed Nov 13 22:17:11 2013 From: hannes.hoerl at snowreporter.com (=?ISO-8859-1?Q?Hannes_H=F6rl?=) Date: Wed, 13 Nov 2013 12:17:11 +0100 Subject: Protocol Version Exchange: the comments field and an idea how to use it Message-ID: <52835FB7.5000407@snowreporter.com> Good day! As stated in [1] ("Protocol Version Exchange") there is a "comments" field, which gets transferred in plain text before setting up the encrypted connection. I couldn't find anything specific in which cases one could or should use this field - so i figured I can use it how ever I want. So here is my basic idea: With a command line switch (or configfile entry) the openssh client uses the said comments field to send the (maybe hashed) hostname the user wants to connect to (or any other info for that matter). Now on the serverside one could deploy a small proxy which listens on the default ssh port. When receiving the Protocol Version and this comment this proxy could decide (based on the unencrypted stuff) where to pipe this connection to. This could be used to route ssh connection from a frontend machine to a backend machine without intercepting the encrypted connection and without having multiple ports open which forward to the ssh port on the internal machine. My question: What did I miss - there must be a problem somewhere - This shouldn't interfere with any other standards compliant ssh server - I can't really think of any security problems (given there are no errors in the implementation itself) - Looking through the openssh code it shouldn't be to hard to implement for the openssh-client - Said proxy should be relatively easy to implement too - I think this could be extremely helpful for various situations Any input on this idea would be very much appreciated! Thank you & bye, Hannes [1] https://tools.ietf.org/html/rfc4253#section-4.2 From jmales at gmail.com Wed Nov 13 23:25:55 2013 From: jmales at gmail.com (J's Mail) Date: Wed, 13 Nov 2013 07:25:55 -0500 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <52835FB7.5000407@snowreporter.com> References: <52835FB7.5000407@snowreporter.com> Message-ID: What you describe can be configured today, with no development effort at all. external proxy/gateway sshd_config: Match Group proxy_user ForceCommand /bin/false client machine ssh_config: Host private_internal_machine hostname 192.168.1.22 ProxyCommand ssh proxy -W %h:%p --- This particular configuration would require the proxy/gateway machine to have credentials configured for the desired accounts. This may or may not be a stumbling block. I would argue that you want some form of access control and a nice PAM configuration would allow you to centrally manage both the proxy and the internal machine accounts. A note on the sshd configuration of the proxy machine: This isn't strictly necessary. What it is intended to accomplish is deny local access on the proxy machine. This could be enforced in other ways. I'd like to hear comments on this. Currently, the ssh client can specify -N, instructing the daemon to not execute a remote command. For the use case here, I'd like to see this enforced from the server side with an sshd option NoCommand. -- Jess On Wed, Nov 13, 2013 at 6:17 AM, Hannes H?rl wrote: > Good day! > > As stated in [1] ("Protocol Version Exchange") there is a "comments" > field, which gets transferred in plain text before setting up the > encrypted connection. I couldn't find anything specific in which cases > one could or should use this field - so i figured I can use it how ever > I want. > > > So here is my basic idea: > > With a command line switch (or configfile entry) the openssh client uses > the said comments field to send the (maybe hashed) hostname the user > wants to connect to (or any other info for that matter). > > Now on the serverside one could deploy a small proxy which listens on > the default ssh port. When receiving the Protocol Version and this > comment this proxy could decide (based on the unencrypted stuff) where > to pipe this connection to. This could be used to route ssh connection > from a frontend machine to a backend machine without intercepting the > encrypted connection and without having multiple ports open which > forward to the ssh port on the internal machine. > > > My question: > > What did I miss - there must be a problem somewhere > - This shouldn't interfere with any other standards compliant ssh server > - I can't really think of any security problems (given there are no > errors in the implementation itself) > - Looking through the openssh code it shouldn't be to hard to > implement for the openssh-client > - Said proxy should be relatively easy to implement too > - I think this could be extremely helpful for various situations > > Any input on this idea would be very much appreciated! > > Thank you & bye, > Hannes > > > [1] https://tools.ietf.org/html/rfc4253#section-4.2 > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev > On Wed, Nov 13, 2013 at 6:17 AM, Hannes H?rl wrote: > Good day! > > As stated in [1] ("Protocol Version Exchange") there is a "comments" > field, which gets transferred in plain text before setting up the > encrypted connection. I couldn't find anything specific in which cases > one could or should use this field - so i figured I can use it how ever > I want. > > > So here is my basic idea: > > With a command line switch (or configfile entry) the openssh client uses > the said comments field to send the (maybe hashed) hostname the user > wants to connect to (or any other info for that matter). > > Now on the serverside one could deploy a small proxy which listens on > the default ssh port. When receiving the Protocol Version and this > comment this proxy could decide (based on the unencrypted stuff) where > to pipe this connection to. This could be used to route ssh connection > from a frontend machine to a backend machine without intercepting the > encrypted connection and without having multiple ports open which > forward to the ssh port on the internal machine. > > > My question: > > What did I miss - there must be a problem somewhere > - This shouldn't interfere with any other standards compliant ssh server > - I can't really think of any security problems (given there are no > errors in the implementation itself) > - Looking through the openssh code it shouldn't be to hard to > implement for the openssh-client > - Said proxy should be relatively easy to implement too > - I think this could be extremely helpful for various situations > > Any input on this idea would be very much appreciated! > > Thank you & bye, > Hannes > > > [1] https://tools.ietf.org/html/rfc4253#section-4.2 > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev > From hannes.hoerl at snowreporter.com Thu Nov 14 00:25:44 2013 From: hannes.hoerl at snowreporter.com (=?ISO-8859-1?Q?Hannes_H=F6rl?=) Date: Wed, 13 Nov 2013 14:25:44 +0100 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: References: <52835FB7.5000407@snowreporter.com> Message-ID: <52837DD8.5050901@snowreporter.com> Hi. Just to be clear: This all is just my imaginary use case. Anyhow, I think you could call the thing I'm thinking about "poor man's SNI[0] for SSH" ... So my question(s) rephrased: Why isn't there anything like SNI for SSH? For security reasons? Is there no demand? Is there a better solution which I don't know of? On 11/13/2013 01:25 PM, J's Mail wrote: > What you describe can be configured today, with no development effort at > all. > [...] > client machine > ssh_config: > Host private_internal_machine > hostname 192.168.1.22 > ProxyCommand ssh proxy -W %h:%p If I understand this right this would make a ssh connection to the proxy, terminate it there - and make a second connection from the client machine to the backend machine, tunneled through the first ssh connection, right? So anything needed (account, certs, ...) to authenticate a user on the backend machine needs to be setup and available on the proxy too. > This particular configuration would require the proxy/gateway machine to > have credentials configured for the desired accounts. This may or may > not be a stumbling block. For my imaginary use case, the backend machines would be (virtual) hosts for customers, friends, ... where I have no idea about e.g. user accounts (or for that matter: I'd have no idea about anything going on on those hosts). The only thing I know is, if there is a host with a certain hostname in my backend network or not. If so I'd like to pipe through the connection to the desired host. I don't want to have any ssh connection to the proxy machine itself. Therefor my idea: the magical '-H'[1] switch (or some setting in the ssh_config). $ ssh -H user at www.mybackendhost.com www.mybackendhost.com resolves to the IP of the proxy (there is already HAProxy running for proxying HTTP ...). The '-H' option appends the hostname (www.mybackendhost.com again) to the "Protocol Exchange String"[2]. My proxy daemon then just has to listen to the first line (or first 255 chars or whatever) and, based on this, can determine where the connection has to go. It doesn't have to have any idea about ssh, encryption, ... itself. After finding the desired host, my proxy daemon just has to sit between the client and the backend host and forward data coming from either side to the other - without knowing, what this data is actually about. Thank you for your input anyways! Bye, Hannes [0] https://en.wikipedia.org/wiki/Server_Name_Indication [1] I just picked '-H' because it seams to be unused by now [2] for example: SSH-2.0-OpenSSH_6.4p1 www.mybackendhost.com From arjenbax at googlemail.com Thu Nov 14 01:17:12 2013 From: arjenbax at googlemail.com (Arjen Bax) Date: Wed, 13 Nov 2013 15:17:12 +0100 Subject: [bugreport+patch] ssh-keygen option -V does not accept single time spec Message-ID: Hi, I noticed that the option -V of ssh-keygen (specify certificate validity period) did not behave as documented: A validity interval may consist of a single time, indicating that the certificate is valid beginning now and expiring at that time, or may consist of two times separated by a colon to indicate an explicit time interval. In openssh-6.4p1, the former format, with a single time spec, caused a fatal error message to be printed (Invalid certificate life specification 20140101). Please find a patch below that solves this issue and will accept both single and double time specifications. ==== BEGINNING OF PATCH ==== diff --git a/ssh-keygen.c b/ssh-keygen.c index 03c444d..994dea7 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1701,10 +1701,19 @@ parse_absolute_time(const char *s) return (u_int64_t)tt; } +static u_int64_t +parse_rel_or_abs_time(const char *s, time_t now) +{ + if (*s == '-' || *s == '+') + return parse_relative_time(s, now); + else + return parse_absolute_time(s); +} + static void parse_cert_times(char *timespec) { - char *from, *to; + char *ts_cp, *from, *to; time_t now = time(NULL); int64_t secs; @@ -1722,29 +1731,37 @@ parse_cert_times(char *timespec) } /* - * from:to, where + * A validity interval may consist of a single time, indicating that + * the certificate is valid beginning now and expiring at that time, or + * may consist of two times separated by a colon to indicate an + * explicit time interval. + * [from:]to, where * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS */ - from = xstrdup(timespec); - to = strchr(from, ':'); - if (to == NULL || from == to || *(to + 1) == '\0') + ts_cp = xstrdup(timespec); + to = strchr(ts_cp, ':'); + if (NULL == to) { + /* no ':' found, only end time specified */ + from = "+0"; + to = ts_cp; + } else { + /* ':' found, end start time at this point and start end time + * immediately after. + */ + from = ts_cp; + *to = '\0'; + to++; + } + if (0 == *from || 0 == *to) fatal("Invalid certificate life specification %s", timespec); - *to++ = '\0'; - if (*from == '-' || *from == '+') - cert_valid_from = parse_relative_time(from, now); - else - cert_valid_from = parse_absolute_time(from); - - if (*to == '-' || *to == '+') - cert_valid_to = parse_relative_time(to, cert_valid_from); - else - cert_valid_to = parse_absolute_time(to); + cert_valid_from = parse_rel_or_abs_time(from, now); + cert_valid_to = parse_rel_or_abs_time(to, now); if (cert_valid_to <= cert_valid_from) fatal("Empty certificate validity interval"); - free(from); + free(ts_cp); } static void ==== END OF PATCH ==== Vriendelijke groet / Kind regards / Vennlig hilsen, Arjen Bax From jmales at gmail.com Thu Nov 14 03:56:52 2013 From: jmales at gmail.com (J's Mail) Date: Wed, 13 Nov 2013 11:56:52 -0500 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <52837DD8.5050901@snowreporter.com> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> Message-ID: Hannes, So my question(s) rephrased: > Why isn't there anything like SNI for SSH? For security reasons? Is there > no demand? Is there a better solution which I don't know of? I have no idea if such a thing has been discussed before. Personally, while I understand the use case, I'm not convinced of the need to modify ssh to accommodate it. > If I understand this right this would make a ssh connection to the proxy, > terminate it there - and make a second connection from the client machine > to the backend machine, tunneled through the first ssh connection, right? > So anything needed (account, certs, ...) to authenticate a user on the > backend machine needs to be setup and available on the proxy too. > > You appear to understand my suggestion correctly; it does stipulate account management on the proxy/gateway. Alternative solutions for the use case you describe (with varying requirements): - iptable rules - certain ip ranges can be automatically forwarded to certain hosts and ports. Configure your proxy/gateway thus. requirement: known source addresses - corkscrew - tunnels SSH traffic through an HTTP proxy. You'd have to reverse the direction of the proxy, and that seems wonky to me, so be sure you lock it down as much as possible. requirement: http proxy - sslh - (http://www.rutschle.net/tech/sslh.shtml) this project self-describes as an application demultiplexer. As far as I'm aware, it doesn't handle your use case, but I would present the use case to them, they may be able to accommodate. Even if the comment field were implemented, you'd need a server application to read and interpret the host. This project already meets that need. Modifying sshd, especially with the lack of authentication, seems unnecessary. Thank you for your input anyways! > You're welcome, thanks for asking the question; I like exploring the edges of what's possible. -- Jess From peter at stuge.se Thu Nov 14 04:24:00 2013 From: peter at stuge.se (Peter Stuge) Date: Wed, 13 Nov 2013 18:24:00 +0100 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <52837DD8.5050901@snowreporter.com> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> Message-ID: <20131113172400.28889.qmail@stuge.se> Hannes H?rl wrote: >> Host private_internal_machine >> hostname 192.168.1.22 >> ProxyCommand ssh proxy -W %h:%p > > If I understand this right this would make a ssh connection to the proxy, > terminate it there - and make a second connection from the client machine > to the backend machine, tunneled through the first ssh connection, right? Yes. > So anything needed (account, certs, ...) to authenticate a user on the > backend machine needs to be setup and available on the proxy too. No. The second logical connection is (as you write) indeed between the client and the backend machine. Both the proxy and the backend machine individually and independently authenticate their respective connection, and in both cases it is the client machine on the other end. > For my imaginary use case, the backend machines would be (virtual) hosts > for customers, friends, ... where I have no idea about e.g. user accounts > (or for that matter: I'd have no idea about anything going on on those > hosts). > The only thing I know is, if there is a host with a certain hostname in my > backend network or not. If so I'd like to pipe through the connection to > the desired host. I don't want to have any ssh connection to the proxy > machine itself. Why have a proxy if it allows to connect to any backend machine without authenticating the request anyway? //Peter From dkg at fifthhorseman.net Thu Nov 14 04:59:07 2013 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Wed, 13 Nov 2013 12:59:07 -0500 Subject: SNI for ssh [was: Re: Protocol Version Exchange: the comments field and an idea how to use it] In-Reply-To: <52837DD8.5050901@snowreporter.com> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> Message-ID: <5283BDEB.8060401@fifthhorseman.net> On 11/13/2013 08:25 AM, Hannes H?rl wrote: > This all is just my imaginary use case. Anyhow, I think you could call > the thing I'm thinking about "poor man's SNI[0] for SSH" ... I'm not sure why it would be "poor man's" -- your proposal sounds very similar to SNI from TLS. There is currently a lot of discussion on tls at ietf.org about problems with SNI -- in particular, that it leaks the name of the desired host to a passive network attacker. In general, it's wise to be wary of cleartext connection hints that are used in the negotiation of a secure channel. One of the ideas from the discussion about TLS is to move SNI within a layer of crypto based on an anonymous DHE handshake, which puts it out of reach of a passive attacker (of course, an active attacker who is willing to cause a connection failure can still extract this information). Note that SNI (in either TLS or in your SSH proposal) is not "negotiated" in a strict sense. Is it offered by the client to the server in the clear, in the hopes that it will be supported by the server (but willing to be ignored if it is not supported). > So my question(s) rephrased: > Why isn't there anything like SNI for SSH? For security reasons? Is > there no demand? Is there a better solution which I don't know of? Is it worth having clients advertise the server's name in the clear on the network if there is no proxy in use? Your proposal neatly avoids this question by making it disabled by default. You should also realize that some distributors patch their clients to add a comment string there anyway (e.g. Debian openssh puts "Debian" in the comment there). So your proxy could get quite confused if it tries to hand the connection off to the "Debian" backend. If this is a space for hiding other sorts of cleartext connection "hints", then you probably want to distinguish your "SNI" hint from other hints. you could perhaps do this by declaring it with a specialized prefix, like "Host:", to distinguish it from othe uses of the comment field. That way a comment like "limburger Host:server.example.net" would be cleanly parseable. If you decide this is really something that you want, I'd recommend modeling your change on the patches that added the VersionAddendum configuration option for sshd (but you're talking about adding it to ssh): (from ChangeLog): djm at cvs.openbsd.org 2012/04/12 02:42:32 [servconf.c servconf.h sshd.c sshd_config sshd_config.5] VersionAddendum option to allow server operators to append some arbitrary text to the SSH-... banner; ok deraadt@ "don't care" markus@ and then making that string interpret the standard %-escapes, so a client who wants to use this feature could do: ssh -oVersionAddendum=Host:%h server.example.net That configuration option seems flexible and generic enough that it would fit with the rest of the ssh interface (and it would enable distros like debian to drop diffs like debian/patches/package-versioning.patch in favor of a one-line addition to /etc/ssh/ssh_config). I'm not convinced that a feature like this is worth allocating one of the few remaining short option flags (-H) though :) Another thought about your proposed proxy: ssh's DH key exchange results in a shared secret based on the exact contents of a bunch of stuff, including the connection strings. Either all of your backend servers need to offer the exact same connection string as your proxy offers, or your proxy needs to wait to receive the client's connection string before forwarding the connection to the backend server. If you choose the former, then when dealing with system upgrades, you'll need to upgrade your entire server farm at once, so that the connection strings stay synchronised. This kind of "flag day" makes maintenance difficult. If you choose the latter, and there are any SSH clients out there that wait for the server's connection string before sending their own, then those clients will deadlock when connecting to your proxy. --dkg -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 1027 bytes Desc: OpenPGP digital signature URL: From mstone at mathom.us Thu Nov 14 05:05:27 2013 From: mstone at mathom.us (Michael Stone) Date: Wed, 13 Nov 2013 13:05:27 -0500 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <20131113172400.28889.qmail@stuge.se> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <20131113172400.28889.qmail@stuge.se> Message-ID: <167fd566-4c8e-11e3-bdf8-001cc0cda50c@msgid.mathom.us> On Wed, Nov 13, 2013 at 06:24:00PM +0100, you wrote: >Why have a proxy if it allows to connect to any backend machine >without authenticating the request anyway? Because IPv6 isn't widely deployed yet. From peter at stuge.se Thu Nov 14 05:22:19 2013 From: peter at stuge.se (Peter Stuge) Date: Wed, 13 Nov 2013 19:22:19 +0100 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <167fd566-4c8e-11e3-bdf8-001cc0cda50c@msgid.mathom.us> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <20131113172400.28889.qmail@stuge.se> <167fd566-4c8e-11e3-bdf8-001cc0cda50c@msgid.mathom.us> Message-ID: <20131113182219.2341.qmail@stuge.se> Michael Stone wrote: >> Why have a proxy if it allows to connect to any backend machine >> without authenticating the request anyway? > > Because IPv6 isn't widely deployed yet. The imaginary use case was virtual hosts with a www. hostname example, so the backend machines are presumably reachable at least on one port already. //Peter From hannes.hoerl at snowreporter.com Thu Nov 14 06:10:54 2013 From: hannes.hoerl at snowreporter.com (=?ISO-8859-1?Q?Hannes_H=F6rl?=) Date: Wed, 13 Nov 2013 20:10:54 +0100 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <5283BDEB.8060401@fifthhorseman.net> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <5283BDEB.8060401@fifthhorseman.net> Message-ID: <5283CEBE.2070802@snowreporter.com> Hi. On 11/13/2013 06:59 PM, Daniel Kahn Gillmor wrote: > On 11/13/2013 08:25 AM, Hannes H?rl wrote: > >> This all is just my imaginary use case. Anyhow, I think you could call >> the thing I'm thinking about "poor man's SNI[0] for SSH" ... > > I'm not sure why it would be "poor man's" -- your proposal sounds very > similar to SNI from TLS. "poor man's" because its just fiddling with the "Protocol Version Exchange" string and not introducing new stuff in the protocol ... > [ ... Problems of SNI ... ] > Note that SNI (in either TLS or in your SSH proposal) is not > "negotiated" in a strict sense. Is it offered by the client to the > server in the clear, in the hopes that it will be supported by the > server (but willing to be ignored if it is not supported). Yes, that's exactly how i thought about it ... >> So my question(s) rephrased: >> Why isn't there anything like SNI for SSH? For security reasons? Is >> there no demand? Is there a better solution which I don't know of? > Is it worth having clients advertise the server's name in the clear on > the network if there is no proxy in use? Your proposal neatly avoids > this question by making it disabled by default. What is the problem, when the client advertises it? In the case that I'm thinking about the DNS advertises the fact, that some hostname is in my net directly or NATed or whatever) anyways. If I'd setup portforwarding on different ports on the proxy to reach the sshd of the different backend machines and having multiple hostnames (for my http proxy) point to the same proxy IP, how would this be safer? Anyways, I wouldn't make it a default to send the hostname, because it's just ignored on any server except my proxy thingy and therefor useless in all other cases. > You should also realize that some distributors patch their clients to > add a comment string there anyway (e.g. Debian openssh puts "Debian" in > the comment there). Ah ok, I didn't realize this while playing with (obviously) just the unpatched version. > So your proxy could get quite confused if it tries > to hand the connection off to the "Debian" backend. Mh. If the proxy doesn't know about a backend machine "Debian" there would be no problem. If there is a backend machine with said name a connection would be established, but the user (hopefully) cannot authenticate. > If this is a space for hiding other sorts of cleartext connection "hints", then you > probably want to distinguish your "SNI" hint from other hints. you > could perhaps do this by declaring it with a specialized prefix, like > "Host:", to distinguish it from othe uses of the comment field. That > way a comment like "limburger Host:server.example.net" would be cleanly > parseable. That's something I thought about an would somehow be possible. But If I understood the RFC, the max length is 253 (\r\n not counted). So packing to much stuff in the comments field isn't even possible anyway. > If you decide this is really something that you want, I'd recommend > modeling your change on the patches that added the VersionAddendum > configuration option for sshd (but you're talking about adding it to ssh): > > (from ChangeLog): > djm at cvs.openbsd.org 2012/04/12 02:42:32 > [servconf.c servconf.h sshd.c sshd_config sshd_config.5] > VersionAddendum option to allow server operators to append some arbitrary > text to the SSH-... banner; ok deraadt@ "don't care" markus@ > > and then making that string interpret the standard %-escapes, so a > client who wants to use this feature could do: > > ssh -oVersionAddendum=Host:%h server.example.net > > That configuration option seems flexible and generic enough that it > would fit with the rest of the ssh interface (and it would enable > distros like debian to drop diffs like > debian/patches/package-versioning.patch in favor of a one-line addition > to /etc/ssh/ssh_config). Thank you for the pointer, I will look into this. But anyway: the information would have to be transfered in the first (unencrypted) line. And - even more when distributors or other clients already use the comment field - space there is rare. Any other implementation of my idea would need updates in the protocol itself, and I think i don't want to got there ... ;) > I'm not convinced that a feature like this is > orth allocating one of the few remaining short option flags (-H) though :) Haha ... I think you realized, this was just an example ... :) > Another thought about your proposed proxy: ssh's DH key exchange results > in a shared secret based on the exact contents of a bunch of stuff, > including the connection strings. Either all of your backend servers > need to offer the exact same connection string as your proxy offers, or > your proxy needs to wait to receive the client's connection string > before forwarding the connection to the backend server. Yes. > If you choose the former, then when dealing with system upgrades [...] No, that's not what I intended. This sure is a PITA. > If you choose the latter, and there are any SSH clients out there that > wait for the server's connection string before sending their own, then > those clients will deadlock when connecting to your proxy. Ok. Somehow I was convinced, the client has to send its connection string first; I must have gotten confused at some point. After your description and a short test it's obvious this is not the case. So my approach (waiting for the client to send its connection string) would exactly have the problems you pointed out. However, you answered most of the questions I had in mind and pointed out problems with my approach. Thank you very much! Nevertheless: I definitely would like to have some kind of SNI or similar for SSH :) Thanks again & bye, Hannes From hannes.hoerl at snowreporter.com Thu Nov 14 06:16:03 2013 From: hannes.hoerl at snowreporter.com (=?ISO-8859-1?Q?Hannes_H=F6rl?=) Date: Wed, 13 Nov 2013 20:16:03 +0100 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <20131113182219.2341.qmail@stuge.se> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <20131113172400.28889.qmail@stuge.se> <167fd566-4c8e-11e3-bdf8-001cc0cda50c@msgid.mathom.us> <20131113182219.2341.qmail@stuge.se> Message-ID: <5283CFF3.9040708@snowreporter.com> Hi On 11/13/2013 07:22 PM, Peter Stuge wrote: > Michael Stone wrote: >>> Why have a proxy if it allows to connect to any backend machine >>> without authenticating the request anyway? >> >> Because IPv6 isn't widely deployed yet. > > The imaginary use case was virtual hosts with a www. hostname > example, so the backend machines are presumably reachable at least > on one port already. No. I thought of the case, where the backend machines are not reachable from the outside, but http goes through haproxy or something similar. So from the outside hostnames point to the proxy, but on the internal network they resolve to their internal IPs. Hannes From peter at stuge.se Thu Nov 14 06:30:31 2013 From: peter at stuge.se (Peter Stuge) Date: Wed, 13 Nov 2013 20:30:31 +0100 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <5283CFF3.9040708@snowreporter.com> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <20131113172400.28889.qmail@stuge.se> <167fd566-4c8e-11e3-bdf8-001cc0cda50c@msgid.mathom.us> <20131113182219.2341.qmail@stuge.se> <5283CFF3.9040708@snowreporter.com> Message-ID: <20131113193031.7675.qmail@stuge.se> Hannes H?rl wrote: >> The imaginary use case was virtual hosts with a www. hostname >> example, so the backend machines are presumably reachable at least >> on one port already. > > No. I thought of the case, where the backend machines are not reachable > from the outside, but http goes through haproxy or something similar. > So from the outside hostnames point to the proxy, but on the internal > network they resolve to their internal IPs. Ie. they are reachable. Why not make the HTTP proxy understand CONNECT (if it doesn't already) and use a suitable proxycommand in your ssh config? //Peter From dkg at fifthhorseman.net Thu Nov 14 08:03:32 2013 From: dkg at fifthhorseman.net (Daniel Kahn Gillmor) Date: Wed, 13 Nov 2013 16:03:32 -0500 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <5283CEBE.2070802@snowreporter.com> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <5283BDEB.8060401@fifthhorseman.net> <5283CEBE.2070802@snowreporter.com> Message-ID: <5283E924.8000301@fifthhorseman.net> On 11/13/2013 02:10 PM, Hannes H?rl wrote: > [dkg wrote:] >> If you choose the latter, and there are any SSH clients out there that >> wait for the server's connection string before sending their own, then >> those clients will deadlock when connecting to your proxy. > > Ok. Somehow I was convinced, the client has to send its connection > string first; I must have gotten confused at some point. After your > description and a short test it's obvious this is not the case. So my > approach (waiting for the client to send its connection string) would > exactly have the problems you pointed out. i don't think the spec insists on an ordering. in fact, i think both are supposed to send their strings immediately, if i'm reading it correctly. My point was that if there is a client that happens to wait for the server string (i don't know of one that does, but i haven't done wide testing for this behavior) then it would deadlock on your proposed proxy. Regards, --dkg -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 1027 bytes Desc: OpenPGP digital signature URL: From mstone at mathom.us Thu Nov 14 08:17:42 2013 From: mstone at mathom.us (Michael Stone) Date: Wed, 13 Nov 2013 16:17:42 -0500 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <20131113193031.7675.qmail@stuge.se> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <20131113172400.28889.qmail@stuge.se> <167fd566-4c8e-11e3-bdf8-001cc0cda50c@msgid.mathom.us> <20131113182219.2341.qmail@stuge.se> <5283CFF3.9040708@snowreporter.com> <20131113193031.7675.qmail@stuge.se> Message-ID: <5ed66f04-4ca8-11e3-bf95-001cc0cda50c@msgid.mathom.us> On Wed, Nov 13, 2013 at 08:30:31PM +0100, you wrote: >Hannes H?rl wrote: >>> The imaginary use case was virtual hosts with a www. hostname >>> example, so the backend machines are presumably reachable at least >>> on one port already. >> >> No. I thought of the case, where the backend machines are not reachable >> from the outside, but http goes through haproxy or something similar. >> So from the outside hostnames point to the proxy, but on the internal >> network they resolve to their internal IPs. > >Ie. they are reachable. The fact that they are reachable via one protocol doesn't change why someone might want a facility in ssh to reach them via a different mechanism. >Why not make the HTTP proxy understand CONNECT (if it doesn't >already) and use a suitable proxycommand in your ssh config? There's certainly more than one way to do it. I'd personally suggest implementing IPv6 and restoring globally unique addressing. From dtucker at zip.com.au Thu Nov 14 11:48:13 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Wed, 13 Nov 2013 19:48:13 -0500 Subject: Protocol Version Exchange: the comments field and an idea how to use it In-Reply-To: <5283E924.8000301@fifthhorseman.net> References: <52835FB7.5000407@snowreporter.com> <52837DD8.5050901@snowreporter.com> <5283BDEB.8060401@fifthhorseman.net> <5283CEBE.2070802@snowreporter.com> <5283E924.8000301@fifthhorseman.net> Message-ID: On Wed, Nov 13, 2013 at 4:03 PM, Daniel Kahn Gillmor wrote: > > i don't think the spec insists on an ordering. in fact, i think both > are supposed to send their strings immediately, if i'm reading it > correctly. Protocol 1 requires that the client wait for the server's banner. Protocol 2 doesn't, but up until relatively recently OpenSSH waited for the banner even if it it was configured to support Protocol 2 only. -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From djm at mindrot.org Thu Nov 14 13:56:31 2013 From: djm at mindrot.org (Damien Miller) Date: Thu, 14 Nov 2013 13:56:31 +1100 (EST) Subject: chacha20+poly1305 authenticated encryption Message-ID: Hi, Here's a diff to implement ChaCha20+Poly1305 as an authenticated encryption mode. It authenticates the packet length and payload, and uses a separate ChaCh20 instance to encrypt the packet length to preserve privacy of packet lengths* while avoiding any decryption oracle for the main packet payload. More details are in the PROTOCOL.chacha20poly1305 file in the diff. It's largely inspired by Adam Langley's similar mode for TLS (http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03) but differs in the padding used for the Poly1305 MAC and in the use of a separate ChaCha20 instance to encrypt the packet lengths. The current implementation uses unoptimised implementations of Poly1305 and ChaCha20, but some basic performance tests have it running at speeds comparable to arcfour128. Comments welcome. -d * the packet lengths will be encrypted, but still subject to measurement by traffic analysis like most other ciphers. Index: PROTOCOL =================================================================== RCS file: /cvs/src/usr.bin/ssh/PROTOCOL,v retrieving revision 1.21 diff -u -p -r1.21 PROTOCOL --- PROTOCOL 17 Oct 2013 00:30:13 -0000 1.21 +++ PROTOCOL 14 Nov 2013 02:10:29 -0000 @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G the exchanged MAC algorithms are ignored and there doesn't have to be a matching MAC. +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption + +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 +as described in PROTOCOL.chacha20poly1305. + 2. Connection protocol changes 2.1. connection: Channel write close extension "eow at openssh.com" Index: PROTOCOL.chacha20poly1305 =================================================================== RCS file: PROTOCOL.chacha20poly1305 diff -N PROTOCOL.chacha20poly1305 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ PROTOCOL.chacha20poly1305 14 Nov 2013 02:10:29 -0000 @@ -0,0 +1,99 @@ +This document describes the chacha20-poly1305 at openssh.com authenticated +encryption cipher supported by OpenSSH. + +Background +---------- + +ChaCha20 is a stream cipher designed by Daniel Bernstein and described +in [1]. 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 stream output. + +Poly1305[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC +that computes a 128 bit integrity tag given a message and a 256 bit key. + +The chacha20-poly1305 at openssh.com combines these two primitives into an +authenticated encryption mode. The construction used is based on that +proposed for TLS by Adam Langley in [3], but differs in the layout of +data passed to the MAC and in the addition of encyption of the packet +lengths. + +Negotiation +----------- + +The chacha20-poly1305 at openssh.com offers both encryption and +authentication. As such, no separate MAC is required. If the +chacha20-poly1305 at openssh.com cipher is selected in key exchange, +the offered MAC algorithms are ignored and no MAC is required to be +negotiated. + +Detailed Construction +--------------------- + +The chacha20-poly1305 at openssh.com 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 K_1 is a pure stream cipher that is used only +to encrypt the 4 byte packet length field. The second instance, +keyed by K_2, is used in conjunction with poly1305 to build an AEAD +(Authenticated Encryption with Associated Data) that is used to encrypt +and authenticate the entire packet. + +Two separate cipher instances are used here so as to keep the packet +lengths confidential but not create an oracle for the packet payload +encryption by decrypting and using the packet length prior to checking +the MAC. By using an independently-keyed cipher instance to encrypt the +length, an active attacker seeking to exploit the packet input handling +as a decryption oracle can learn nothing about the payload contents or +its MAC (assuming key derivation is secure). + +The AEAD is constructed as follows: for each packet, generate a Poly1305 +key by taking the first 256 bits of ChaCha20 stream output generated +using K_2, an IV consisting of the packet sequence number encoded as an +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of +zero. The K_2 ChaCha20 block counter is then set to the little-endian +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used +for encryption of the packet payload. + +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 K_1 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 with the one appended to the packet and the packet +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the +encrypted length. Finally, calculate a MAC tag and append it. + +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 rekeying every 1GB of data +sent or received. If this recommendation is followed, then +chacha20-poly1305 at openssh.com requires no special handling in this area. + +References +---------- + +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein + http://cr.yp.to/chacha/chacha-20080128.pdf + +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein + http://cr.yp.to/mac/poly1305-20050329.pdf + +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 + +$OpenBSD$ + Index: authfile.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/authfile.c,v retrieving revision 1.97 diff -u -p -r1.97 authfile.c --- authfile.c 17 May 2013 00:13:13 -0000 1.97 +++ authfile.c 14 Nov 2013 02:10:29 -0000 @@ -144,7 +144,7 @@ key_private_rsa1_to_blob(Key *key, Buffe cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_ENCRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); @@ -462,7 +462,7 @@ key_parse_private_rsa1(Buffer *blob, con /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(©), buffer_len(©), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); Index: chacha.c =================================================================== RCS file: chacha.c diff -N chacha.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha.c 14 Nov 2013 02:10:29 -0000 @@ -0,0 +1,217 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "chacha.h" + +/* $OpenBSD$ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct chacha_ctx chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) +{ + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} Index: chacha.h =================================================================== RCS file: chacha.h diff -N chacha.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha.h 14 Nov 2013 02:10:29 -0000 @@ -0,0 +1,35 @@ +/* $OpenBSD$ */ + +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_H +#define CHACHA_H + +#include + +struct chacha_ctx { + u_int input[16]; +}; + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, + u_char *c, u_int bytes) + __attribute__((__bounded__(__buffer__, 2, 4))) + __attribute__((__bounded__(__buffer__, 3, 4))); + +#endif /* CHACHA_H */ + Index: chacha20poly1305aead.c =================================================================== RCS file: chacha20poly1305aead.c diff -N chacha20poly1305aead.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha20poly1305aead.c 14 Nov 2013 02:10:30 -0000 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include /* needed for log.h */ +#include +#include /* needed for misc.h */ + +#include "log.h" +#include "misc.h" +#include "chacha20poly1305aead.h" + +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, + const u_char *key, u_int keylen) +{ + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ + fatal("%s: invalid keylen %u", __func__, keylen); + chacha_keysetup(&ctx->main_ctx, key, 256); + chacha_keysetup(&ctx->header_ctx, key + 32, 256); +} + +/* + * cp_aead_crypt() operates as following: + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. + * Theses bytes are treated as additional authenticated data. + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the + * authentication tag. + * This tag is written on encryption and verified on decryption. + * Both 'aadlen' and 'authlen' can be set to 0. + */ +int +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) +{ + u_char seqbuf[8]; + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; + int r = -1; + + /* + * Run ChaCha20 once to generate the Poly1305 key. The IV is the + * packet sequence number. + */ + bzero(poly_key, sizeof(poly_key)); + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->main_ctx, + poly_key, poly_key, sizeof(poly_key)); + /* Set Chacha's block counter to 1 */ + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); + + /* If decrypting, check tag before anything else */ + if (!do_encrypt) { + const u_char *tag = src + aadlen + len; + + poly1305_auth(expected_tag, src, aadlen + len, poly_key); + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) + goto out; + } + /* Crypt additional data */ + if (aadlen) { + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); + } + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, + dest + aadlen, len); + + /* If encrypting, calculate and append tag */ + if (do_encrypt) { + poly1305_auth(dest + aadlen + len, dest, aadlen + len, + poly_key); + } + r = 0; + + out: + bzero(expected_tag, sizeof(expected_tag)); + bzero(seqbuf, sizeof(seqbuf)); + bzero(poly_key, sizeof(poly_key)); + return r; +} + +int +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) +{ + u_char buf[4], seqbuf[8]; + + if (len < 4) + return -1; /* Insufficient length */ + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); + *plenp = get_u32(buf); + return 0; +} + Index: chacha20poly1305aead.h =================================================================== RCS file: chacha20poly1305aead.h diff -N chacha20poly1305aead.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha20poly1305aead.h 14 Nov 2013 02:10:30 -0000 @@ -0,0 +1,41 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) Damien Miller 2013 + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef CHACHA_POLY_AEAD_H +#define CHACHA_POLY_AEAD_H + +#include +#include "chacha.h" +#include "poly1305-donna-unrolled.h" + +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ + +struct chacha_poly_aead_ctx { + struct chacha_ctx main_ctx, header_ctx; +}; + +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, + const u_char *key, u_int keylen) + __attribute__((__bounded__(__buffer__, 2, 3))); +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, + int do_encrypt); +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) + __attribute__((__bounded__(__buffer__, 4, 5))); + +#endif /* CHACHA_POLY_AEAD_H */ Index: cipher.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/cipher.c,v retrieving revision 1.90 diff -u -p -r1.90 cipher.c --- cipher.c 7 Nov 2013 11:58:27 -0000 1.90 +++ cipher.c 14 Nov 2013 02:10:30 -0000 @@ -41,9 +41,11 @@ #include #include +#include #include "xmalloc.h" #include "log.h" +#include "misc.h" #include "cipher.h" extern const EVP_CIPHER *evp_ssh1_bf(void); @@ -58,7 +60,9 @@ struct Cipher { u_int iv_len; /* defaults to block_size */ u_int auth_len; u_int discard_len; - u_int cbc_mode; + u_int flags; +#define CFLAG_CBC (1<<0) +#define CFLAG_CP_AEAD (1<<1) const EVP_CIPHER *(*evptype)(void); }; @@ -88,6 +92,8 @@ static const struct Cipher ciphers[] = { SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, { "aes256-gcm at openssh.com", SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, + { "chacha20-poly1305 at openssh.com", + SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } }; @@ -136,7 +142,12 @@ cipher_authlen(const Cipher *c) u_int cipher_ivlen(const Cipher *c) { - return (c->iv_len ? c->iv_len : c->block_size); + /* + * Default is cipher block size, except for chacha20+poly1305 that + * needs no IV. XXX make iv_len == -1 default? + */ + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? + c->iv_len : c->block_size; } u_int @@ -148,7 +159,7 @@ cipher_get_number(const Cipher *c) u_int cipher_is_cbc(const Cipher *c) { - return (c->cbc_mode); + return (c->flags & CFLAG_CBC) != 0; } u_int @@ -264,8 +275,11 @@ cipher_init(CipherContext *cc, const Cip ivlen, cipher->name); cc->cipher = cipher; + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + cp_aead_init(&cc->cp_ctx, key, keylen); + return; + } type = (*cipher->evptype)(); - EVP_CIPHER_CTX_init(&cc->evp); if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, (do_encrypt == CIPHER_ENCRYPT)) == 0) @@ -310,9 +324,15 @@ cipher_init(CipherContext *cc, const Cip * Both 'aadlen' and 'authlen' can be set to 0. */ void -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen) { + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, + authlen, cc->encrypt) != 0) + fatal("Decryption integrity check failed"); + return; + } if (authlen) { u_char lastiv[1]; @@ -354,10 +374,29 @@ cipher_crypt(CipherContext *cc, u_char * } } +/* + * Extract the packet length for an AEAD cipher, including any decryption + * necessary beforehand. + */ +int +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, + const u_char *cp, u_int len) +{ + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, + cp, len); + if (len < 4) + return -1; + *plenp = get_u32(cp); + return 0; +} + void cipher_cleanup(CipherContext *cc) { - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); } @@ -397,6 +436,8 @@ cipher_get_keyiv_len(const CipherContext if (c->number == SSH_CIPHER_3DES) ivlen = 24; + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + ivlen = 0; else ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); return (ivlen); @@ -408,6 +449,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch const Cipher *c = cc->cipher; int evplen; + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + if (len != 0) + fatal("%s: wrong iv length %d != %d", __func__, len, 0); + return; + } + switch (c->number) { case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: @@ -438,6 +485,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch { const Cipher *c = cc->cipher; int evplen = 0; + + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + return; switch (c->number) { case SSH_CIPHER_SSH2: Index: cipher.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/cipher.h,v retrieving revision 1.41 diff -u -p -r1.41 cipher.h --- cipher.h 7 Nov 2013 11:58:27 -0000 1.41 +++ cipher.h 14 Nov 2013 02:10:30 -0000 @@ -38,6 +38,8 @@ #define CIPHER_H #include +#include "chacha20poly1305aead.h" + /* * Cipher types for SSH-1. New types can be added, but old types should not * be removed for compatibility. The maximum allowed value is 31. @@ -65,7 +67,9 @@ struct Cipher; struct CipherContext { int plaintext; int encrypt; + int is_cp_aead; EVP_CIPHER_CTX evp; + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ const Cipher *cipher; }; @@ -78,8 +82,10 @@ int ciphers_valid(const char *); char *cipher_alg_list(char); void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, const u_char *, u_int, int); -void cipher_crypt(CipherContext *, u_char *, const u_char *, +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, u_int, u_int, u_int); +int cipher_aead_get_length(CipherContext *, u_int *, u_int, + const u_char *, u_int); void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); u_int cipher_blocksize(const Cipher *); Index: myproposal.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/myproposal.h,v retrieving revision 1.33 diff -u -p -r1.33 myproposal.h --- myproposal.h 2 Nov 2013 21:59:15 -0000 1.33 +++ myproposal.h 14 Nov 2013 02:10:30 -0000 @@ -52,6 +52,7 @@ "aes128-ctr,aes192-ctr,aes256-ctr," \ "arcfour256,arcfour128," \ "aes128-gcm at openssh.com,aes256-gcm at openssh.com," \ + "chacha20-poly1305 at openssh.com," \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" #define KEX_DEFAULT_MAC \ Index: packet.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/packet.c,v retrieving revision 1.189 diff -u -p -r1.189 packet.c --- packet.c 8 Nov 2013 00:39:15 -0000 1.189 +++ packet.c 14 Nov 2013 02:10:30 -0000 @@ -702,7 +702,7 @@ packet_send1(void) buffer_append(&active_state->output, buf, 4); cp = buffer_append_space(&active_state->output, buffer_len(&active_state->outgoing_packet)); - cipher_crypt(&active_state->send_context, cp, + cipher_crypt(&active_state->send_context, 0, cp, buffer_ptr(&active_state->outgoing_packet), buffer_len(&active_state->outgoing_packet), 0, 0); @@ -935,8 +935,8 @@ packet_send2_wrapped(void) } /* encrypt packet and append to output buffer. */ cp = buffer_append_space(&active_state->output, len + authlen); - cipher_crypt(&active_state->send_context, cp, - buffer_ptr(&active_state->outgoing_packet), + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, + cp, buffer_ptr(&active_state->outgoing_packet), len - aadlen, aadlen, authlen); /* append unencrypted MAC */ if (mac && mac->enabled) { @@ -1196,7 +1196,7 @@ packet_read_poll1(void) /* Decrypt data to incoming_packet. */ buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, padded_len); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, 0, cp, buffer_ptr(&active_state->input), padded_len, 0, 0); buffer_consume(&active_state->input, padded_len); @@ -1267,10 +1267,12 @@ packet_read_poll2(u_int32_t *seqnr_p) aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; if (aadlen && active_state->packlen == 0) { - if (buffer_len(&active_state->input) < 4) + if (cipher_aead_get_length(&active_state->receive_context, + &active_state->packlen, + active_state->p_read.seqnr, + buffer_ptr(&active_state->input), + buffer_len(&active_state->input)) != 0) return SSH_MSG_NONE; - cp = buffer_ptr(&active_state->input); - active_state->packlen = get_u32(cp); if (active_state->packlen < 1 + 4 || active_state->packlen > PACKET_MAX_SIZE) { #ifdef PACKET_DEBUG @@ -1290,7 +1292,8 @@ packet_read_poll2(u_int32_t *seqnr_p) buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, block_size); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), block_size, 0, 0); cp = buffer_ptr(&active_state->incoming_packet); active_state->packlen = get_u32(cp); @@ -1345,7 +1348,8 @@ packet_read_poll2(u_int32_t *seqnr_p) macbuf = mac_compute(mac, active_state->p_read.seqnr, buffer_ptr(&active_state->input), aadlen + need); cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), need, aadlen, authlen); buffer_consume(&active_state->input, aadlen + need + authlen); /* Index: poly1305-donna-unrolled.c =================================================================== RCS file: poly1305-donna-unrolled.c diff -N poly1305-donna-unrolled.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ poly1305-donna-unrolled.c 14 Nov 2013 02:10:30 -0000 @@ -0,0 +1,154 @@ +/* + * Public Domain poly1305-donna from Andrew M. + * https://github.com/floodyberry/poly1305-donna + */ + +#include +#include + +#include "poly1305-donna-unrolled.h" + +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) + +#define U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LE(p, v) \ + do { \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); \ + } while (0) + +void +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { + uint32_t t0,t1,t2,t3; + uint32_t h0,h1,h2,h3,h4; + uint32_t r0,r1,r2,r3,r4; + uint32_t s1,s2,s3,s4; + uint32_t b, nb; + size_t j; + uint64_t t[5]; + uint64_t f0,f1,f2,f3; + uint32_t g0,g1,g2,g3,g4; + uint64_t c; + unsigned char mp[16]; + + /* clamp key */ + t0 = U8TO32_LE(key+0); + t1 = U8TO32_LE(key+4); + t2 = U8TO32_LE(key+8); + t3 = U8TO32_LE(key+12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (inlen < 16) goto poly1305_donna_atmost15bytes; +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = U8TO32_LE(m-16); + t1 = U8TO32_LE(m-12); + t2 = U8TO32_LE(m-8); + t3 = U8TO32_LE(m-4); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8) | (1 << 24); + + +poly1305_donna_mul: + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); + h0 += b * 5; + + if (inlen >= 16) goto poly1305_donna_16bytes; + + /* final bytes */ +poly1305_donna_atmost15bytes: + if (!inlen) goto poly1305_donna_finish; + + for (j = 0; j < inlen; j++) mp[j] = m[j]; + mp[j++] = 1; + for (; j < 16; j++) mp[j] = 0; + inlen = 0; + + t0 = U8TO32_LE(mp+0); + t1 = U8TO32_LE(mp+4); + t2 = U8TO32_LE(mp+8); + t3 = U8TO32_LE(mp+12); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); + + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); + U32TO8_LE(&out[12], f3); +} Index: poly1305-donna-unrolled.h =================================================================== RCS file: poly1305-donna-unrolled.h diff -N poly1305-donna-unrolled.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ poly1305-donna-unrolled.h 14 Nov 2013 02:10:30 -0000 @@ -0,0 +1,22 @@ +/* $OpenBSD$ */ + +/* + * Public Domain poly1305-donna from Andrew M. + * https://github.com/floodyberry/poly1305-donna + */ + +#ifndef POLY1305_H +#define POLY1305_H + +#include + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, + const u_char key[POLY1305_KEYLEN]) + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) + __attribute__((__bounded__(__buffer__, 2, 3))) + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); + +#endif /* POLY1305_H */ Index: lib/Makefile =================================================================== RCS file: /cvs/src/usr.bin/ssh/lib/Makefile,v retrieving revision 1.68 diff -u -p -r1.68 Makefile --- lib/Makefile 2 Nov 2013 21:59:15 -0000 1.68 +++ lib/Makefile 14 Nov 2013 02:10:30 -0000 @@ -13,7 +13,8 @@ SRCS= authfd.c authfile.c bufaux.c bufec ssh-dss.c ssh-rsa.c ssh-ecdsa.c dh.c kexdh.c kexgex.c kexecdh.c \ kexdhc.c kexgexc.c kexecdhc.c msg.c progressmeter.c dns.c \ monitor_fdpass.c umac.c addrmatch.c schnorr.c jpake.c ssh-pkcs11.c \ - krl.c smult_curve25519_ref.c kexc25519.c kexc25519c.c + krl.c smult_curve25519_ref.c kexc25519.c kexc25519c.c \ + chacha.c poly1305-donna-unrolled.c chacha20poly1305aead.c SRCS+= umac128.c CLEANFILES+= umac128.c From djm at mindrot.org Thu Nov 14 13:59:56 2013 From: djm at mindrot.org (Damien Miller) Date: Thu, 14 Nov 2013 13:59:56 +1100 (EST) Subject: [PATCH] curve25519-sha256@libssh.org key exchange proposal In-Reply-To: <527B5DAF.50106@0xbadc0de.be> References: <5241F449.8070407@0xbadc0de.be> <5278FFCB.7080809@0xbadc0de.be> <527B5DAF.50106@0xbadc0de.be> Message-ID: On Thu, 7 Nov 2013, Aris Adamantiadis wrote: > Le 7/11/13 00:28, mancha a ?crit : > > > > That sounds like a great complement to aes{128,256}-gcm at openssh.com. > > Have you been tracking his progress so far? e.g.: > > http://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=9a8646510b > > I am not very comfortable with aes*-gcm at openssh.com because the packet > len is not encrypted under the claim that it is not possible to do both > encryption and authentication on the length field. I believe that's not > true, a competing authenticated encryption mechanism should fix this > (e.g. by sending an authentication token on both every encrypted length > and packet payload). > > This unencrypted length thing brings SSH2 back to the SSH1 days where it > was trivial to sniff the length of a password. Contrary to what the RFC > tells, sending ignore packets doesn't help. You might be interested in the ChaCha20+Poly1305 proposal diff that I just sent to the openssh-unix-dev@ mailing list. It uses a separate stream cipher instance to encrypt the packet lengths. -d From loganaden at gmail.com Thu Nov 14 20:54:40 2013 From: loganaden at gmail.com (Loganaden Velvindron) Date: Thu, 14 Nov 2013 13:54:40 +0400 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: Awesome :-) On Thu, Nov 14, 2013 at 6:56 AM, Damien Miller wrote: > Hi, > > Here's a diff to implement ChaCha20+Poly1305 as an authenticated > encryption mode. It authenticates the packet length and payload, and > uses a separate ChaCh20 instance to encrypt the packet length to > preserve privacy of packet lengths* while avoiding any decryption > oracle for the main packet payload. More details are in the > PROTOCOL.chacha20poly1305 file in the diff. > > It's largely inspired by Adam Langley's similar mode for TLS > (http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03) but > differs in the padding used for the Poly1305 MAC and in the use of a > separate ChaCha20 instance to encrypt the packet lengths. > > The current implementation uses unoptimised implementations of Poly1305 > and ChaCha20, but some basic performance tests have it running at speeds > comparable to arcfour128. > > Comments welcome. > > -d > > * the packet lengths will be encrypted, but still subject to measurement > by traffic analysis like most other ciphers. > > Index: PROTOCOL > =================================================================== > RCS file: /cvs/src/usr.bin/ssh/PROTOCOL,v > retrieving revision 1.21 > diff -u -p -r1.21 PROTOCOL > --- PROTOCOL 17 Oct 2013 00:30:13 -0000 1.21 > +++ PROTOCOL 14 Nov 2013 02:10:29 -0000 > @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G > the exchanged MAC algorithms are ignored and there doesn't have to be > a matching MAC. > > +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption > + > +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 > +as described in PROTOCOL.chacha20poly1305. > + > 2. Connection protocol changes > > 2.1. connection: Channel write close extension "eow at openssh.com" > Index: PROTOCOL.chacha20poly1305 > =================================================================== > RCS file: PROTOCOL.chacha20poly1305 > diff -N PROTOCOL.chacha20poly1305 > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ PROTOCOL.chacha20poly1305 14 Nov 2013 02:10:29 -0000 > @@ -0,0 +1,99 @@ > +This document describes the chacha20-poly1305 at openssh.com authenticated > +encryption cipher supported by OpenSSH. > + > +Background > +---------- > + > +ChaCha20 is a stream cipher designed by Daniel Bernstein and described > +in [1]. 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 stream output. > + > +Poly1305[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC > +that computes a 128 bit integrity tag given a message and a 256 bit key. > + > +The chacha20-poly1305 at openssh.com combines these two primitives into an > +authenticated encryption mode. The construction used is based on that > +proposed for TLS by Adam Langley in [3], but differs in the layout of > +data passed to the MAC and in the addition of encyption of the packet > +lengths. > + > +Negotiation > +----------- > + > +The chacha20-poly1305 at openssh.com offers both encryption and > +authentication. As such, no separate MAC is required. If the > +chacha20-poly1305 at openssh.com cipher is selected in key exchange, > +the offered MAC algorithms are ignored and no MAC is required to be > +negotiated. > + > +Detailed Construction > +--------------------- > + > +The chacha20-poly1305 at openssh.com 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 K_1 is a pure stream cipher that is used only > +to encrypt the 4 byte packet length field. The second instance, > +keyed by K_2, is used in conjunction with poly1305 to build an AEAD > +(Authenticated Encryption with Associated Data) that is used to encrypt > +and authenticate the entire packet. > + > +Two separate cipher instances are used here so as to keep the packet > +lengths confidential but not create an oracle for the packet payload > +encryption by decrypting and using the packet length prior to checking > +the MAC. By using an independently-keyed cipher instance to encrypt the > +length, an active attacker seeking to exploit the packet input handling > +as a decryption oracle can learn nothing about the payload contents or > +its MAC (assuming key derivation is secure). > + > +The AEAD is constructed as follows: for each packet, generate a Poly1305 > +key by taking the first 256 bits of ChaCha20 stream output generated > +using K_2, an IV consisting of the packet sequence number encoded as an > +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of > +zero. The K_2 ChaCha20 block counter is then set to the little-endian > +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used > +for encryption of the packet payload. > + > +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 K_1 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 with the one appended to the packet and the packet > +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the > +encrypted length. Finally, calculate a MAC tag and append it. > + > +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 rekeying every 1GB of data > +sent or received. If this recommendation is followed, then > +chacha20-poly1305 at openssh.com requires no special handling in this area. > + > +References > +---------- > + > +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein > + http://cr.yp.to/chacha/chacha-20080128.pdf > + > +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein > + http://cr.yp.to/mac/poly1305-20050329.pdf > + > +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley > + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 > + > +$OpenBSD$ > + > Index: authfile.c > =================================================================== > RCS file: /cvs/src/usr.bin/ssh/authfile.c,v > retrieving revision 1.97 > diff -u -p -r1.97 authfile.c > --- authfile.c 17 May 2013 00:13:13 -0000 1.97 > +++ authfile.c 14 Nov 2013 02:10:29 -0000 > @@ -144,7 +144,7 @@ key_private_rsa1_to_blob(Key *key, Buffe > > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_ENCRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > @@ -462,7 +462,7 @@ key_parse_private_rsa1(Buffer *blob, con > /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_DECRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(©), buffer_len(©), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > Index: chacha.c > =================================================================== > RCS file: chacha.c > diff -N chacha.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.c 14 Nov 2013 02:10:29 -0000 > @@ -0,0 +1,217 @@ > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > + > +#include "chacha.h" > + > +/* $OpenBSD$ */ > + > +typedef unsigned char u8; > +typedef unsigned int u32; > + > +typedef struct chacha_ctx chacha_ctx; > + > +#define U8C(v) (v##U) > +#define U32C(v) (v##U) > + > +#define U8V(v) ((u8)(v) & U8C(0xFF)) > +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) > + > +#define ROTL32(v, n) \ > + (U32V((v) << (n)) | ((v) >> (32 - (n)))) > + > +#define U8TO32_LITTLE(p) \ > + (((u32)((p)[0]) ) | \ > + ((u32)((p)[1]) << 8) | \ > + ((u32)((p)[2]) << 16) | \ > + ((u32)((p)[3]) << 24)) > + > +#define U32TO8_LITTLE(p, v) \ > + do { \ > + (p)[0] = U8V((v) ); \ > + (p)[1] = U8V((v) >> 8); \ > + (p)[2] = U8V((v) >> 16); \ > + (p)[3] = U8V((v) >> 24); \ > + } while (0) > + > +#define ROTATE(v,c) (ROTL32(v,c)) > +#define XOR(v,w) ((v) ^ (w)) > +#define PLUS(v,w) (U32V((v) + (w))) > +#define PLUSONE(v) (PLUS((v),1)) > + > +#define QUARTERROUND(a,b,c,d) \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); > + > +static const char sigma[16] = "expand 32-byte k"; > +static const char tau[16] = "expand 16-byte k"; > + > +void > +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) > +{ > + const char *constants; > + > + x->input[4] = U8TO32_LITTLE(k + 0); > + x->input[5] = U8TO32_LITTLE(k + 4); > + x->input[6] = U8TO32_LITTLE(k + 8); > + x->input[7] = U8TO32_LITTLE(k + 12); > + if (kbits == 256) { /* recommended */ > + k += 16; > + constants = sigma; > + } else { /* kbits == 128 */ > + constants = tau; > + } > + x->input[8] = U8TO32_LITTLE(k + 0); > + x->input[9] = U8TO32_LITTLE(k + 4); > + x->input[10] = U8TO32_LITTLE(k + 8); > + x->input[11] = U8TO32_LITTLE(k + 12); > + x->input[0] = U8TO32_LITTLE(constants + 0); > + x->input[1] = U8TO32_LITTLE(constants + 4); > + x->input[2] = U8TO32_LITTLE(constants + 8); > + x->input[3] = U8TO32_LITTLE(constants + 12); > +} > + > +void > +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) > +{ > + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); > + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); > + x->input[14] = U8TO32_LITTLE(iv + 0); > + x->input[15] = U8TO32_LITTLE(iv + 4); > +} > + > +void > +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) > +{ > + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; > + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; > + u8 *ctarget = NULL; > + u8 tmp[64]; > + u_int i; > + > + if (!bytes) return; > + > + j0 = x->input[0]; > + j1 = x->input[1]; > + j2 = x->input[2]; > + j3 = x->input[3]; > + j4 = x->input[4]; > + j5 = x->input[5]; > + j6 = x->input[6]; > + j7 = x->input[7]; > + j8 = x->input[8]; > + j9 = x->input[9]; > + j10 = x->input[10]; > + j11 = x->input[11]; > + j12 = x->input[12]; > + j13 = x->input[13]; > + j14 = x->input[14]; > + j15 = x->input[15]; > + > + for (;;) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) tmp[i] = m[i]; > + m = tmp; > + ctarget = c; > + c = tmp; > + } > + x0 = j0; > + x1 = j1; > + x2 = j2; > + x3 = j3; > + x4 = j4; > + x5 = j5; > + x6 = j6; > + x7 = j7; > + x8 = j8; > + x9 = j9; > + x10 = j10; > + x11 = j11; > + x12 = j12; > + x13 = j13; > + x14 = j14; > + x15 = j15; > + for (i = 20;i > 0;i -= 2) { > + QUARTERROUND( x0, x4, x8,x12) > + QUARTERROUND( x1, x5, x9,x13) > + QUARTERROUND( x2, x6,x10,x14) > + QUARTERROUND( x3, x7,x11,x15) > + QUARTERROUND( x0, x5,x10,x15) > + QUARTERROUND( x1, x6,x11,x12) > + QUARTERROUND( x2, x7, x8,x13) > + QUARTERROUND( x3, x4, x9,x14) > + } > + x0 = PLUS(x0,j0); > + x1 = PLUS(x1,j1); > + x2 = PLUS(x2,j2); > + x3 = PLUS(x3,j3); > + x4 = PLUS(x4,j4); > + x5 = PLUS(x5,j5); > + x6 = PLUS(x6,j6); > + x7 = PLUS(x7,j7); > + x8 = PLUS(x8,j8); > + x9 = PLUS(x9,j9); > + x10 = PLUS(x10,j10); > + x11 = PLUS(x11,j11); > + x12 = PLUS(x12,j12); > + x13 = PLUS(x13,j13); > + x14 = PLUS(x14,j14); > + x15 = PLUS(x15,j15); > + > + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); > + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); > + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); > + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); > + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); > + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); > + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); > + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); > + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); > + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); > + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); > + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); > + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); > + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); > + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); > + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); > + > + j12 = PLUSONE(j12); > + if (!j12) { > + j13 = PLUSONE(j13); > + /* stopping at 2^70 bytes per nonce is user's responsibility */ > + } > + > + U32TO8_LITTLE(c + 0,x0); > + U32TO8_LITTLE(c + 4,x1); > + U32TO8_LITTLE(c + 8,x2); > + U32TO8_LITTLE(c + 12,x3); > + U32TO8_LITTLE(c + 16,x4); > + U32TO8_LITTLE(c + 20,x5); > + U32TO8_LITTLE(c + 24,x6); > + U32TO8_LITTLE(c + 28,x7); > + U32TO8_LITTLE(c + 32,x8); > + U32TO8_LITTLE(c + 36,x9); > + U32TO8_LITTLE(c + 40,x10); > + U32TO8_LITTLE(c + 44,x11); > + U32TO8_LITTLE(c + 48,x12); > + U32TO8_LITTLE(c + 52,x13); > + U32TO8_LITTLE(c + 56,x14); > + U32TO8_LITTLE(c + 60,x15); > + > + if (bytes <= 64) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; > + } > + x->input[12] = j12; > + x->input[13] = j13; > + return; > + } > + bytes -= 64; > + c += 64; > + m += 64; > + } > +} > Index: chacha.h > =================================================================== > RCS file: chacha.h > diff -N chacha.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.h 14 Nov 2013 02:10:29 -0000 > @@ -0,0 +1,35 @@ > +/* $OpenBSD$ */ > + > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > + > +#ifndef CHACHA_H > +#define CHACHA_H > + > +#include > + > +struct chacha_ctx { > + u_int input[16]; > +}; > + > +#define CHACHA_MINKEYLEN 16 > +#define CHACHA_NONCELEN 8 > +#define CHACHA_CTRLEN 8 > +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) > +#define CHACHA_BLOCKLEN 64 > + > +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); > +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) > + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); > +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, > + u_char *c, u_int bytes) > + __attribute__((__bounded__(__buffer__, 2, 4))) > + __attribute__((__bounded__(__buffer__, 3, 4))); > + > +#endif /* CHACHA_H */ > + > Index: chacha20poly1305aead.c > =================================================================== > RCS file: chacha20poly1305aead.c > diff -N chacha20poly1305aead.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.c 14 Nov 2013 02:10:30 -0000 > @@ -0,0 +1,110 @@ > +/* > + * Copyright (c) 2013 Damien Miller > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include > +#include /* needed for log.h */ > +#include > +#include /* needed for misc.h */ > + > +#include "log.h" > +#include "misc.h" > +#include "chacha20poly1305aead.h" > + > +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, > + const u_char *key, u_int keylen) > +{ > + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ > + fatal("%s: invalid keylen %u", __func__, keylen); > + chacha_keysetup(&ctx->main_ctx, key, 256); > + chacha_keysetup(&ctx->header_ctx, key + 32, 256); > +} > + > +/* > + * cp_aead_crypt() operates as following: > + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. > + * Theses bytes are treated as additional authenticated data. > + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. > + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the > + * authentication tag. > + * This tag is written on encryption and verified on decryption. > + * Both 'aadlen' and 'authlen' can be set to 0. > + */ > +int > +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, > + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) > +{ > + u_char seqbuf[8]; > + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ > + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; > + int r = -1; > + > + /* > + * Run ChaCha20 once to generate the Poly1305 key. The IV is the > + * packet sequence number. > + */ > + bzero(poly_key, sizeof(poly_key)); > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->main_ctx, > + poly_key, poly_key, sizeof(poly_key)); > + /* Set Chacha's block counter to 1 */ > + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); > + > + /* If decrypting, check tag before anything else */ > + if (!do_encrypt) { > + const u_char *tag = src + aadlen + len; > + > + poly1305_auth(expected_tag, src, aadlen + len, poly_key); > + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) > + goto out; > + } > + /* Crypt additional data */ > + if (aadlen) { > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); > + } > + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, > + dest + aadlen, len); > + > + /* If encrypting, calculate and append tag */ > + if (do_encrypt) { > + poly1305_auth(dest + aadlen + len, dest, aadlen + len, > + poly_key); > + } > + r = 0; > + > + out: > + bzero(expected_tag, sizeof(expected_tag)); > + bzero(seqbuf, sizeof(seqbuf)); > + bzero(poly_key, sizeof(poly_key)); > + return r; > +} > + > +int > +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > +{ > + u_char buf[4], seqbuf[8]; > + > + if (len < 4) > + return -1; /* Insufficient length */ > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); > + *plenp = get_u32(buf); > + return 0; > +} > + > Index: chacha20poly1305aead.h > =================================================================== > RCS file: chacha20poly1305aead.h > diff -N chacha20poly1305aead.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.h 14 Nov 2013 02:10:30 -0000 > @@ -0,0 +1,41 @@ > +/* $OpenBSD$ */ > + > +/* > + * Copyright (c) Damien Miller 2013 > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > +#ifndef CHACHA_POLY_AEAD_H > +#define CHACHA_POLY_AEAD_H > + > +#include > +#include "chacha.h" > +#include "poly1305-donna-unrolled.h" > + > +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ > + > +struct chacha_poly_aead_ctx { > + struct chacha_ctx main_ctx, header_ctx; > +}; > + > +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, > + const u_char *key, u_int keylen) > + __attribute__((__bounded__(__buffer__, 2, 3))); > +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, > + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, > + int do_encrypt); > +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > + __attribute__((__bounded__(__buffer__, 4, 5))); > + > +#endif /* CHACHA_POLY_AEAD_H */ > Index: cipher.c > =================================================================== > RCS file: /cvs/src/usr.bin/ssh/cipher.c,v > retrieving revision 1.90 > diff -u -p -r1.90 cipher.c > --- cipher.c 7 Nov 2013 11:58:27 -0000 1.90 > +++ cipher.c 14 Nov 2013 02:10:30 -0000 > @@ -41,9 +41,11 @@ > > #include > #include > +#include > > #include "xmalloc.h" > #include "log.h" > +#include "misc.h" > #include "cipher.h" > > extern const EVP_CIPHER *evp_ssh1_bf(void); > @@ -58,7 +60,9 @@ struct Cipher { > u_int iv_len; /* defaults to block_size */ > u_int auth_len; > u_int discard_len; > - u_int cbc_mode; > + u_int flags; > +#define CFLAG_CBC (1<<0) > +#define CFLAG_CP_AEAD (1<<1) > const EVP_CIPHER *(*evptype)(void); > }; > > @@ -88,6 +92,8 @@ static const struct Cipher ciphers[] = { > SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, > { "aes256-gcm at openssh.com", > SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, > + { "chacha20-poly1305 at openssh.com", > + SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, > > { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } > }; > @@ -136,7 +142,12 @@ cipher_authlen(const Cipher *c) > u_int > cipher_ivlen(const Cipher *c) > { > - return (c->iv_len ? c->iv_len : c->block_size); > + /* > + * Default is cipher block size, except for chacha20+poly1305 that > + * needs no IV. XXX make iv_len == -1 default? > + */ > + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? > + c->iv_len : c->block_size; > } > > u_int > @@ -148,7 +159,7 @@ cipher_get_number(const Cipher *c) > u_int > cipher_is_cbc(const Cipher *c) > { > - return (c->cbc_mode); > + return (c->flags & CFLAG_CBC) != 0; > } > > u_int > @@ -264,8 +275,11 @@ cipher_init(CipherContext *cc, const Cip > ivlen, cipher->name); > cc->cipher = cipher; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + cp_aead_init(&cc->cp_ctx, key, keylen); > + return; > + } > type = (*cipher->evptype)(); > - > EVP_CIPHER_CTX_init(&cc->evp); > if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, > (do_encrypt == CIPHER_ENCRYPT)) == 0) > @@ -310,9 +324,15 @@ cipher_init(CipherContext *cc, const Cip > * Both 'aadlen' and 'authlen' can be set to 0. > */ > void > -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, > +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, > u_int len, u_int aadlen, u_int authlen) > { > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, > + authlen, cc->encrypt) != 0) > + fatal("Decryption integrity check failed"); > + return; > + } > if (authlen) { > u_char lastiv[1]; > > @@ -354,10 +374,29 @@ cipher_crypt(CipherContext *cc, u_char * > } > } > > +/* > + * Extract the packet length for an AEAD cipher, including any decryption > + * necessary beforehand. > + */ > +int > +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, > + const u_char *cp, u_int len) > +{ > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, > + cp, len); > + if (len < 4) > + return -1; > + *plenp = get_u32(cp); > + return 0; > +} > + > void > cipher_cleanup(CipherContext *cc) > { > - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); > + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); > } > > @@ -397,6 +436,8 @@ cipher_get_keyiv_len(const CipherContext > > if (c->number == SSH_CIPHER_3DES) > ivlen = 24; > + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + ivlen = 0; > else > ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); > return (ivlen); > @@ -408,6 +449,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch > const Cipher *c = cc->cipher; > int evplen; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (len != 0) > + fatal("%s: wrong iv length %d != %d", __func__, len, 0); > + return; > + } > + > switch (c->number) { > case SSH_CIPHER_SSH2: > case SSH_CIPHER_DES: > @@ -438,6 +485,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch > { > const Cipher *c = cc->cipher; > int evplen = 0; > + > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return; > > switch (c->number) { > case SSH_CIPHER_SSH2: > Index: cipher.h > =================================================================== > RCS file: /cvs/src/usr.bin/ssh/cipher.h,v > retrieving revision 1.41 > diff -u -p -r1.41 cipher.h > --- cipher.h 7 Nov 2013 11:58:27 -0000 1.41 > +++ cipher.h 14 Nov 2013 02:10:30 -0000 > @@ -38,6 +38,8 @@ > #define CIPHER_H > > #include > +#include "chacha20poly1305aead.h" > + > /* > * Cipher types for SSH-1. New types can be added, but old types should not > * be removed for compatibility. The maximum allowed value is 31. > @@ -65,7 +67,9 @@ struct Cipher; > struct CipherContext { > int plaintext; > int encrypt; > + int is_cp_aead; > EVP_CIPHER_CTX evp; > + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ > const Cipher *cipher; > }; > > @@ -78,8 +82,10 @@ int ciphers_valid(const char *); > char *cipher_alg_list(char); > void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, > const u_char *, u_int, int); > -void cipher_crypt(CipherContext *, u_char *, const u_char *, > +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, > u_int, u_int, u_int); > +int cipher_aead_get_length(CipherContext *, u_int *, u_int, > + const u_char *, u_int); > void cipher_cleanup(CipherContext *); > void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); > u_int cipher_blocksize(const Cipher *); > Index: myproposal.h > =================================================================== > RCS file: /cvs/src/usr.bin/ssh/myproposal.h,v > retrieving revision 1.33 > diff -u -p -r1.33 myproposal.h > --- myproposal.h 2 Nov 2013 21:59:15 -0000 1.33 > +++ myproposal.h 14 Nov 2013 02:10:30 -0000 > @@ -52,6 +52,7 @@ > "aes128-ctr,aes192-ctr,aes256-ctr," \ > "arcfour256,arcfour128," \ > "aes128-gcm at openssh.com,aes256-gcm at openssh.com," \ > + "chacha20-poly1305 at openssh.com," \ > "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ > "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" > #define KEX_DEFAULT_MAC \ > Index: packet.c > =================================================================== > RCS file: /cvs/src/usr.bin/ssh/packet.c,v > retrieving revision 1.189 > diff -u -p -r1.189 packet.c > --- packet.c 8 Nov 2013 00:39:15 -0000 1.189 > +++ packet.c 14 Nov 2013 02:10:30 -0000 > @@ -702,7 +702,7 @@ packet_send1(void) > buffer_append(&active_state->output, buf, 4); > cp = buffer_append_space(&active_state->output, > buffer_len(&active_state->outgoing_packet)); > - cipher_crypt(&active_state->send_context, cp, > + cipher_crypt(&active_state->send_context, 0, cp, > buffer_ptr(&active_state->outgoing_packet), > buffer_len(&active_state->outgoing_packet), 0, 0); > > @@ -935,8 +935,8 @@ packet_send2_wrapped(void) > } > /* encrypt packet and append to output buffer. */ > cp = buffer_append_space(&active_state->output, len + authlen); > - cipher_crypt(&active_state->send_context, cp, > - buffer_ptr(&active_state->outgoing_packet), > + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, > + cp, buffer_ptr(&active_state->outgoing_packet), > len - aadlen, aadlen, authlen); > /* append unencrypted MAC */ > if (mac && mac->enabled) { > @@ -1196,7 +1196,7 @@ packet_read_poll1(void) > /* Decrypt data to incoming_packet. */ > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, padded_len); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, 0, cp, > buffer_ptr(&active_state->input), padded_len, 0, 0); > > buffer_consume(&active_state->input, padded_len); > @@ -1267,10 +1267,12 @@ packet_read_poll2(u_int32_t *seqnr_p) > aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; > > if (aadlen && active_state->packlen == 0) { > - if (buffer_len(&active_state->input) < 4) > + if (cipher_aead_get_length(&active_state->receive_context, > + &active_state->packlen, > + active_state->p_read.seqnr, > + buffer_ptr(&active_state->input), > + buffer_len(&active_state->input)) != 0) > return SSH_MSG_NONE; > - cp = buffer_ptr(&active_state->input); > - active_state->packlen = get_u32(cp); > if (active_state->packlen < 1 + 4 || > active_state->packlen > PACKET_MAX_SIZE) { > #ifdef PACKET_DEBUG > @@ -1290,7 +1292,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, > block_size); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), block_size, 0, 0); > cp = buffer_ptr(&active_state->incoming_packet); > active_state->packlen = get_u32(cp); > @@ -1345,7 +1348,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > macbuf = mac_compute(mac, active_state->p_read.seqnr, > buffer_ptr(&active_state->input), aadlen + need); > cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), need, aadlen, authlen); > buffer_consume(&active_state->input, aadlen + need + authlen); > /* > Index: poly1305-donna-unrolled.c > =================================================================== > RCS file: poly1305-donna-unrolled.c > diff -N poly1305-donna-unrolled.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.c 14 Nov 2013 02:10:30 -0000 > @@ -0,0 +1,154 @@ > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#include > +#include > + > +#include "poly1305-donna-unrolled.h" > + > +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) > + > +#define U8TO32_LE(p) \ > + (((uint32_t)((p)[0])) | \ > + ((uint32_t)((p)[1]) << 8) | \ > + ((uint32_t)((p)[2]) << 16) | \ > + ((uint32_t)((p)[3]) << 24)) > + > +#define U32TO8_LE(p, v) \ > + do { \ > + (p)[0] = (uint8_t)((v)); \ > + (p)[1] = (uint8_t)((v) >> 8); \ > + (p)[2] = (uint8_t)((v) >> 16); \ > + (p)[3] = (uint8_t)((v) >> 24); \ > + } while (0) > + > +void > +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { > + uint32_t t0,t1,t2,t3; > + uint32_t h0,h1,h2,h3,h4; > + uint32_t r0,r1,r2,r3,r4; > + uint32_t s1,s2,s3,s4; > + uint32_t b, nb; > + size_t j; > + uint64_t t[5]; > + uint64_t f0,f1,f2,f3; > + uint32_t g0,g1,g2,g3,g4; > + uint64_t c; > + unsigned char mp[16]; > + > + /* clamp key */ > + t0 = U8TO32_LE(key+0); > + t1 = U8TO32_LE(key+4); > + t2 = U8TO32_LE(key+8); > + t3 = U8TO32_LE(key+12); > + > + /* precompute multipliers */ > + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; > + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; > + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; > + r3 = t2 & 0x3f03fff; t3 >>= 8; > + r4 = t3 & 0x00fffff; > + > + s1 = r1 * 5; > + s2 = r2 * 5; > + s3 = r3 * 5; > + s4 = r4 * 5; > + > + /* init state */ > + h0 = 0; > + h1 = 0; > + h2 = 0; > + h3 = 0; > + h4 = 0; > + > + /* full blocks */ > + if (inlen < 16) goto poly1305_donna_atmost15bytes; > +poly1305_donna_16bytes: > + m += 16; > + inlen -= 16; > + > + t0 = U8TO32_LE(m-16); > + t1 = U8TO32_LE(m-12); > + t2 = U8TO32_LE(m-8); > + t3 = U8TO32_LE(m-4); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8) | (1 << 24); > + > + > +poly1305_donna_mul: > + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); > + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); > + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); > + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); > + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); > + > + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); > + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); > + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); > + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); > + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); > + h0 += b * 5; > + > + if (inlen >= 16) goto poly1305_donna_16bytes; > + > + /* final bytes */ > +poly1305_donna_atmost15bytes: > + if (!inlen) goto poly1305_donna_finish; > + > + for (j = 0; j < inlen; j++) mp[j] = m[j]; > + mp[j++] = 1; > + for (; j < 16; j++) mp[j] = 0; > + inlen = 0; > + > + t0 = U8TO32_LE(mp+0); > + t1 = U8TO32_LE(mp+4); > + t2 = U8TO32_LE(mp+8); > + t3 = U8TO32_LE(mp+12); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8); > + > + goto poly1305_donna_mul; > + > +poly1305_donna_finish: > + b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; > + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; > + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; > + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; > + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; > + > + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; > + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; > + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; > + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; > + g4 = h4 + b - (1 << 26); > + > + b = (g4 >> 31) - 1; > + nb = ~b; > + h0 = (h0 & nb) | (g0 & b); > + h1 = (h1 & nb) | (g1 & b); > + h2 = (h2 & nb) | (g2 & b); > + h3 = (h3 & nb) | (g3 & b); > + h4 = (h4 & nb) | (g4 & b); > + > + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); > + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); > + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); > + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); > + > + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); > + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); > + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); > + U32TO8_LE(&out[12], f3); > +} > Index: poly1305-donna-unrolled.h > =================================================================== > RCS file: poly1305-donna-unrolled.h > diff -N poly1305-donna-unrolled.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.h 14 Nov 2013 02:10:30 -0000 > @@ -0,0 +1,22 @@ > +/* $OpenBSD$ */ > + > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#ifndef POLY1305_H > +#define POLY1305_H > + > +#include > + > +#define POLY1305_KEYLEN 32 > +#define POLY1305_TAGLEN 16 > + > +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, > + const u_char key[POLY1305_KEYLEN]) > + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) > + __attribute__((__bounded__(__buffer__, 2, 3))) > + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); > + > +#endif /* POLY1305_H */ > Index: lib/Makefile > =================================================================== > RCS file: /cvs/src/usr.bin/ssh/lib/Makefile,v > retrieving revision 1.68 > diff -u -p -r1.68 Makefile > --- lib/Makefile 2 Nov 2013 21:59:15 -0000 1.68 > +++ lib/Makefile 14 Nov 2013 02:10:30 -0000 > @@ -13,7 +13,8 @@ SRCS= authfd.c authfile.c bufaux.c bufec > ssh-dss.c ssh-rsa.c ssh-ecdsa.c dh.c kexdh.c kexgex.c kexecdh.c \ > kexdhc.c kexgexc.c kexecdhc.c msg.c progressmeter.c dns.c \ > monitor_fdpass.c umac.c addrmatch.c schnorr.c jpake.c ssh-pkcs11.c \ > - krl.c smult_curve25519_ref.c kexc25519.c kexc25519c.c > + krl.c smult_curve25519_ref.c kexc25519.c kexc25519c.c \ > + chacha.c poly1305-donna-unrolled.c chacha20poly1305aead.c > > SRCS+= umac128.c > CLEANFILES+= umac128.c > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- This message is strictly personal and the opinions expressed do not represent those of my employers, either past or present. From cloos at jhcloos.com Fri Nov 15 06:26:33 2013 From: cloos at jhcloos.com (James Cloos) Date: Thu, 14 Nov 2013 14:26:33 -0500 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: (Damien Miller's message of "Thu, 14 Nov 2013 13:56:31 +1100 (EST)") References: Message-ID: >>>>> "DM" == Damien Miller writes: DM> Here's a diff to implement ChaCha20+Poly1305 as an authenticated DM> encryption mode. It authenticates the packet length and payload, DM> and uses a separate ChaCh20 instance to encrypt the packet length DM> to preserve privacy of packet lengths* while avoiding any decryption DM> oracle for the main packet payload. Cool. I'd like to test it out, but for logistics reasons I'll have to do so on a linux box. Is anything written on what is needed to convert from the openbsd cvs tree to the portable tree? Or do you have a version of the patch applicable to the portable's cvs? -JimC -- James Cloos OpenPGP: 1024D/ED7DAEA6 From mancha1 at hush.com Fri Nov 15 11:32:05 2013 From: mancha1 at hush.com (mancha) Date: Fri, 15 Nov 2013 00:32:05 +0000 (UTC) Subject: chacha20+poly1305 authenticated encryption References: Message-ID: Damien Miller mindrot.org> writes: > Here's a diff to implement ChaCha20+Poly1305 as an authenticated > encryption mode. Many thanks for this gem to play with over the weekend! James Cloos jhcloos.com> writes: > I'd like to test it out...do you have a version of the patch > applicable to the portable's cvs? I've ported Damien's work to OpenSSH 6.4p1 and placed at: http://sf.net/projects/mancha/files/misc/openssh-6.4p1-ChaCha20+Poly1305.diff --mancha From djm at mindrot.org Fri Nov 15 21:03:11 2013 From: djm at mindrot.org (Damien Miller) Date: Fri, 15 Nov 2013 21:03:11 +1100 (EST) Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Thu, 14 Nov 2013, James Cloos wrote: > >>>>> "DM" == Damien Miller writes: > > DM> Here's a diff to implement ChaCha20+Poly1305 as an authenticated > DM> encryption mode. It authenticates the packet length and payload, > DM> and uses a separate ChaCh20 instance to encrypt the packet length > DM> to preserve privacy of packet lengths* while avoiding any decryption > DM> oracle for the main packet payload. > > Cool. > > I'd like to test it out, but for logistics reasons I'll have to do so on > a linux box. Is anything written on what is needed to convert from the > openbsd cvs tree to the portable tree? Or do you have a version of the > patch applicable to the portable's cvs? Here's one that applies to portable OpenSSH. Also available at http://www.mindrot.org/files/chachapoly1305_04_portable.diff Index: Makefile.in =================================================================== RCS file: /var/cvs/openssh/Makefile.in,v retrieving revision 1.344 diff -u -p -r1.344 Makefile.in --- Makefile.in 8 Nov 2013 13:17:41 -0000 1.344 +++ Makefile.in 15 Nov 2013 00:08:29 -0000 @@ -74,7 +74,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \ - kexc25519.o kexc25519c.o + kexc25519.o kexc25519c.o chacha.o chacha20poly1305aead.o \ + poly1305-donna-unrolled.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ sshconnect.o sshconnect1.o sshconnect2.o mux.o \ Index: PROTOCOL =================================================================== RCS file: /var/cvs/openssh/PROTOCOL,v retrieving revision 1.20 diff -u -p -r1.20 PROTOCOL --- PROTOCOL 17 Oct 2013 00:48:53 -0000 1.20 +++ PROTOCOL 15 Nov 2013 00:08:29 -0000 @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G the exchanged MAC algorithms are ignored and there doesn't have to be a matching MAC. +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption + +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 +as described in PROTOCOL.chacha20poly1305. + 2. Connection protocol changes 2.1. connection: Channel write close extension "eow at openssh.com" Index: PROTOCOL.chacha20poly1305 =================================================================== RCS file: PROTOCOL.chacha20poly1305 diff -N PROTOCOL.chacha20poly1305 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ PROTOCOL.chacha20poly1305 15 Nov 2013 00:08:29 -0000 @@ -0,0 +1,99 @@ +This document describes the chacha20-poly1305 at openssh.com authenticated +encryption cipher supported by OpenSSH. + +Background +---------- + +ChaCha20 is a stream cipher designed by Daniel Bernstein and described +in [1]. 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 stream output. + +Poly1305[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC +that computes a 128 bit integrity tag given a message and a 256 bit key. + +The chacha20-poly1305 at openssh.com combines these two primitives into an +autenticated encryption mode. The construction used is based on that +proposed for TLS by Adam Langley in [3], but differs in the layout of +data passed to the MAC and in the addition of encyption of the packet +lengths. + +Negotiation +----------- + +The chacha20-poly1305 at openssh.com offers both encryption and +authentication. As such, no separate MAC is required. If the +chacha20-poly1305 at openssh.com cipher is selected in key exchange, +the offered MAC algorithms are ignored and no MAC is required to be +negotiated. + +Detailed Construction +--------------------- + +The chacha20-poly1305 at openssh.com cipher required 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 K_1 is a pure stream cipher that is used only +to encrypt the 4 byte packet length field. The second instance, +keyed by K_2, is used in conjunction with poly1305 to build an AEAD +(Authenticated Encryption with Associated Data) that is used to encrypt +and authenticate entire packet. + +Two separate cipher instances are used here so as to keep the packet +lengths confidential but not create an oracle for the packet payload +encryption by decrypting and using the packet length prior to checking +the MAC. By using an independently-keyed cipher instance to encrypt the +length, an active attacker seeking to exploit the packet input handling +as a decryption oracle can learn nothing about the payload contents or +its MAC (assuming key derivation is secure). + +The AEAD is constructed as follows: for each packet, generate a Poly1305 +key by taking the first 256 bits of ChaCha20 stream output generated +using K_2, an IV consisting of the packet sequence number encoded as an +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of +zero. The K_2 ChaCha20 block counter is then set to the little-endian +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used +for encryption of the packet payload. + +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 K_1 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 with the one appended to the packet and the packet +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the +encrypted length. Finally, calculate a MAC tag and append it. + +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 rekeying every 1GB of data +sent or received. If this recommendation is followed, then +chacha20-poly1305 at openssh.com requires no special handling in this area. + +References +---------- + +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein + http://cr.yp.to/chacha/chacha-20080128.pdf + +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein + http://cr.yp.to/mac/poly1305-20050329.pdf + +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 + +$OpenBSD$ + Index: authfile.c =================================================================== RCS file: /var/cvs/openssh/authfile.c,v retrieving revision 1.101 diff -u -p -r1.101 authfile.c --- authfile.c 1 Jun 2013 21:31:18 -0000 1.101 +++ authfile.c 15 Nov 2013 00:08:29 -0000 @@ -149,7 +149,7 @@ key_private_rsa1_to_blob(Key *key, Buffe cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_ENCRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); @@ -473,7 +473,7 @@ key_parse_private_rsa1(Buffer *blob, con /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(©), buffer_len(©), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); Index: chacha.c =================================================================== RCS file: chacha.c diff -N chacha.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha.c 15 Nov 2013 00:08:29 -0000 @@ -0,0 +1,217 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ +#include +#include "chacha.h" + +/* $OpenBSD$ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct chacha_ctx chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) +{ + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} Index: chacha.h =================================================================== RCS file: chacha.h diff -N chacha.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha.h 15 Nov 2013 00:08:29 -0000 @@ -0,0 +1,35 @@ +/* $OpenBSD$ */ + +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_H +#define CHACHA_H + +#include + +struct chacha_ctx { + u_int input[16]; +}; + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, + u_char *c, u_int bytes) + __attribute__((__bounded__(__buffer__, 2, 4))) + __attribute__((__bounded__(__buffer__, 3, 4))); + +#endif /* CHACHA_H */ + Index: chacha20poly1305aead.c =================================================================== RCS file: chacha20poly1305aead.c diff -N chacha20poly1305aead.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha20poly1305aead.c 15 Nov 2013 00:08:29 -0000 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include /* needed for misc.h */ +#include /* needed for log.h */ +#include +#include /* needed for misc.h */ + +#include "log.h" +#include "misc.h" +#include "chacha20poly1305aead.h" + +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, + const u_char *key, u_int keylen) +{ + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ + fatal("%s: invalid keylen %u", __func__, keylen); + chacha_keysetup(&ctx->main_ctx, key, 256); + chacha_keysetup(&ctx->header_ctx, key + 32, 256); +} + +/* + * cp_aead_crypt() operates as following: + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. + * Theses bytes are treated as additional authenticated data. + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the + * authentication tag. + * This tag is written on encryption and verified on decryption. + * Both 'aadlen' and 'authlen' can be set to 0. + */ +int +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) +{ + u_char seqbuf[8]; + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; + int r = -1; + + /* + * Run ChaCha20 once to generate the Poly1305 key. The IV is the + * packet sequence number. + */ + bzero(poly_key, sizeof(poly_key)); + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->main_ctx, + poly_key, poly_key, sizeof(poly_key)); + /* Set Chacha's block counter to 1 */ + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); + + /* If decrypting, check tag before anything else */ + if (!do_encrypt) { + const u_char *tag = src + aadlen + len; + + poly1305_auth(expected_tag, src, aadlen + len, poly_key); + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) + goto out; + } + /* Crypt additional data */ + if (aadlen) { + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); + } + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, + dest + aadlen, len); + + /* If encrypting, calculate and append tag */ + if (do_encrypt) { + poly1305_auth(dest + aadlen + len, dest, aadlen + len, + poly_key); + } + r = 0; + + out: + bzero(expected_tag, sizeof(expected_tag)); + bzero(seqbuf, sizeof(seqbuf)); + bzero(poly_key, sizeof(poly_key)); + return r; +} + +int +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) +{ + u_char buf[4], seqbuf[8]; + + if (len < 4) + return -1; /* Insufficient length */ + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); + *plenp = get_u32(buf); + return 0; +} + Index: chacha20poly1305aead.h =================================================================== RCS file: chacha20poly1305aead.h diff -N chacha20poly1305aead.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ chacha20poly1305aead.h 15 Nov 2013 00:08:29 -0000 @@ -0,0 +1,41 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) Damien Miller 2013 + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef CHACHA_POLY_AEAD_H +#define CHACHA_POLY_AEAD_H + +#include +#include "chacha.h" +#include "poly1305-donna-unrolled.h" + +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ + +struct chacha_poly_aead_ctx { + struct chacha_ctx main_ctx, header_ctx; +}; + +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, + const u_char *key, u_int keylen) + __attribute__((__bounded__(__buffer__, 2, 3))); +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, + int do_encrypt); +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) + __attribute__((__bounded__(__buffer__, 4, 5))); + +#endif /* CHACHA_POLY_AEAD_H */ Index: cipher.c =================================================================== RCS file: /var/cvs/openssh/cipher.c,v retrieving revision 1.97 diff -u -p -r1.97 cipher.c --- cipher.c 8 Nov 2013 01:16:50 -0000 1.97 +++ cipher.c 15 Nov 2013 00:08:29 -0000 @@ -43,9 +43,11 @@ #include #include +#include #include "xmalloc.h" #include "log.h" +#include "misc.h" #include "cipher.h" /* compatibility with old or broken OpenSSL versions */ @@ -63,7 +65,9 @@ struct Cipher { u_int iv_len; /* defaults to block_size */ u_int auth_len; u_int discard_len; - u_int cbc_mode; + u_int flags; +#define CFLAG_CBC (1<<0) +#define CFLAG_CP_AEAD (1<<1) const EVP_CIPHER *(*evptype)(void); }; @@ -95,6 +99,8 @@ static const struct Cipher ciphers[] = { { "aes256-gcm at openssh.com", SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, #endif + { "chacha20-poly1305 at openssh.com", + SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } }; @@ -142,7 +148,12 @@ cipher_authlen(const Cipher *c) u_int cipher_ivlen(const Cipher *c) { - return (c->iv_len ? c->iv_len : c->block_size); + /* + * Default is cipher block size, except for chacha20+poly1305 that + * needs no IV. XXX make iv_len == -1 default? + */ + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? + c->iv_len : c->block_size; } u_int @@ -154,7 +165,7 @@ cipher_get_number(const Cipher *c) u_int cipher_is_cbc(const Cipher *c) { - return (c->cbc_mode); + return (c->flags & CFLAG_CBC) != 0; } u_int @@ -274,8 +285,11 @@ cipher_init(CipherContext *cc, const Cip ivlen, cipher->name); cc->cipher = cipher; + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + cp_aead_init(&cc->cp_ctx, key, keylen); + return; + } type = (*cipher->evptype)(); - EVP_CIPHER_CTX_init(&cc->evp); #ifdef SSH_OLD_EVP if (type->key_len > 0 && type->key_len != keylen) { @@ -330,9 +344,15 @@ cipher_init(CipherContext *cc, const Cip * Both 'aadlen' and 'authlen' can be set to 0. */ void -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen) { + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, + authlen, cc->encrypt) != 0) + fatal("Decryption integrity check failed"); + return; + } if (authlen) { u_char lastiv[1]; @@ -374,10 +394,29 @@ cipher_crypt(CipherContext *cc, u_char * } } +/* + * Extract the packet length for an AEAD cipher, including any decryption + * necessary beforehand. + */ +int +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, + const u_char *cp, u_int len) +{ + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, + cp, len); + if (len < 4) + return -1; + *plenp = get_u32(cp); + return 0; +} + void cipher_cleanup(CipherContext *cc) { - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); } @@ -417,6 +456,8 @@ cipher_get_keyiv_len(const CipherContext if (c->number == SSH_CIPHER_3DES) ivlen = 24; + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + ivlen = 0; else ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); return (ivlen); @@ -428,6 +469,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch const Cipher *c = cc->cipher; int evplen; + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + if (len != 0) + fatal("%s: wrong iv length %d != %d", __func__, len, 0); + return; + } + switch (c->number) { case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: @@ -463,6 +510,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch { const Cipher *c = cc->cipher; int evplen = 0; + + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + return; switch (c->number) { case SSH_CIPHER_SSH2: Index: cipher.h =================================================================== RCS file: /var/cvs/openssh/cipher.h,v retrieving revision 1.37 diff -u -p -r1.37 cipher.h --- cipher.h 8 Nov 2013 01:16:50 -0000 1.37 +++ cipher.h 15 Nov 2013 00:08:29 -0000 @@ -38,6 +38,8 @@ #define CIPHER_H #include +#include "chacha20poly1305aead.h" + /* * Cipher types for SSH-1. New types can be added, but old types should not * be removed for compatibility. The maximum allowed value is 31. @@ -65,7 +67,9 @@ struct Cipher; struct CipherContext { int plaintext; int encrypt; + int is_cp_aead; EVP_CIPHER_CTX evp; + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ const Cipher *cipher; }; @@ -78,8 +82,10 @@ int ciphers_valid(const char *); char *cipher_alg_list(char); void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, const u_char *, u_int, int); -void cipher_crypt(CipherContext *, u_char *, const u_char *, +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, u_int, u_int, u_int); +int cipher_aead_get_length(CipherContext *, u_int *, u_int, + const u_char *, u_int); void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); u_int cipher_blocksize(const Cipher *); Index: myproposal.h =================================================================== RCS file: /var/cvs/openssh/myproposal.h,v retrieving revision 1.43 diff -u -p -r1.43 myproposal.h --- myproposal.h 9 Nov 2013 07:39:25 -0000 1.43 +++ myproposal.h 15 Nov 2013 00:08:30 -0000 @@ -104,6 +104,7 @@ "aes128-ctr,aes192-ctr,aes256-ctr," \ "arcfour256,arcfour128," \ AESGCM_CIPHER_MODES \ + "chacha20-poly1305 at openssh.com," \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" Index: packet.c =================================================================== RCS file: /var/cvs/openssh/packet.c,v retrieving revision 1.196 diff -u -p -r1.196 packet.c --- packet.c 8 Nov 2013 01:19:57 -0000 1.196 +++ packet.c 15 Nov 2013 00:08:30 -0000 @@ -713,7 +713,7 @@ packet_send1(void) buffer_append(&active_state->output, buf, 4); cp = buffer_append_space(&active_state->output, buffer_len(&active_state->outgoing_packet)); - cipher_crypt(&active_state->send_context, cp, + cipher_crypt(&active_state->send_context, 0, cp, buffer_ptr(&active_state->outgoing_packet), buffer_len(&active_state->outgoing_packet), 0, 0); @@ -946,8 +946,8 @@ packet_send2_wrapped(void) } /* encrypt packet and append to output buffer. */ cp = buffer_append_space(&active_state->output, len + authlen); - cipher_crypt(&active_state->send_context, cp, - buffer_ptr(&active_state->outgoing_packet), + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, + cp, buffer_ptr(&active_state->outgoing_packet), len - aadlen, aadlen, authlen); /* append unencrypted MAC */ if (mac && mac->enabled) { @@ -1208,7 +1208,7 @@ packet_read_poll1(void) /* Decrypt data to incoming_packet. */ buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, padded_len); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, 0, cp, buffer_ptr(&active_state->input), padded_len, 0, 0); buffer_consume(&active_state->input, padded_len); @@ -1279,10 +1279,12 @@ packet_read_poll2(u_int32_t *seqnr_p) aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; if (aadlen && active_state->packlen == 0) { - if (buffer_len(&active_state->input) < 4) + if (cipher_aead_get_length(&active_state->receive_context, + &active_state->packlen, + active_state->p_read.seqnr, + buffer_ptr(&active_state->input), + buffer_len(&active_state->input)) != 0) return SSH_MSG_NONE; - cp = buffer_ptr(&active_state->input); - active_state->packlen = get_u32(cp); if (active_state->packlen < 1 + 4 || active_state->packlen > PACKET_MAX_SIZE) { #ifdef PACKET_DEBUG @@ -1302,7 +1304,8 @@ packet_read_poll2(u_int32_t *seqnr_p) buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, block_size); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), block_size, 0, 0); cp = buffer_ptr(&active_state->incoming_packet); active_state->packlen = get_u32(cp); @@ -1357,7 +1360,8 @@ packet_read_poll2(u_int32_t *seqnr_p) macbuf = mac_compute(mac, active_state->p_read.seqnr, buffer_ptr(&active_state->input), aadlen + need); cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), need, aadlen, authlen); buffer_consume(&active_state->input, aadlen + need + authlen); /* Index: poly1305-donna-unrolled.c =================================================================== RCS file: poly1305-donna-unrolled.c diff -N poly1305-donna-unrolled.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ poly1305-donna-unrolled.c 15 Nov 2013 00:08:30 -0000 @@ -0,0 +1,154 @@ +/* + * Public Domain poly1305-donna from Andrew M. + * https://github.com/floodyberry/poly1305-donna + */ + +#include +#include + +#include "poly1305-donna-unrolled.h" + +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) + +#define U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LE(p, v) \ + do { \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); \ + } while (0) + +void +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { + uint32_t t0,t1,t2,t3; + uint32_t h0,h1,h2,h3,h4; + uint32_t r0,r1,r2,r3,r4; + uint32_t s1,s2,s3,s4; + uint32_t b, nb; + size_t j; + uint64_t t[5]; + uint64_t f0,f1,f2,f3; + uint32_t g0,g1,g2,g3,g4; + uint64_t c; + unsigned char mp[16]; + + /* clamp key */ + t0 = U8TO32_LE(key+0); + t1 = U8TO32_LE(key+4); + t2 = U8TO32_LE(key+8); + t3 = U8TO32_LE(key+12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (inlen < 16) goto poly1305_donna_atmost15bytes; +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = U8TO32_LE(m-16); + t1 = U8TO32_LE(m-12); + t2 = U8TO32_LE(m-8); + t3 = U8TO32_LE(m-4); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8) | (1 << 24); + + +poly1305_donna_mul: + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); + h0 += b * 5; + + if (inlen >= 16) goto poly1305_donna_16bytes; + + /* final bytes */ +poly1305_donna_atmost15bytes: + if (!inlen) goto poly1305_donna_finish; + + for (j = 0; j < inlen; j++) mp[j] = m[j]; + mp[j++] = 1; + for (; j < 16; j++) mp[j] = 0; + inlen = 0; + + t0 = U8TO32_LE(mp+0); + t1 = U8TO32_LE(mp+4); + t2 = U8TO32_LE(mp+8); + t3 = U8TO32_LE(mp+12); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); + + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); + U32TO8_LE(&out[12], f3); +} Index: poly1305-donna-unrolled.h =================================================================== RCS file: poly1305-donna-unrolled.h diff -N poly1305-donna-unrolled.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ poly1305-donna-unrolled.h 15 Nov 2013 00:08:30 -0000 @@ -0,0 +1,22 @@ +/* $OpenBSD$ */ + +/* + * Public Domain poly1305-donna from Andrew M. + * https://github.com/floodyberry/poly1305-donna + */ + +#ifndef POLY1305_H +#define POLY1305_H + +#include + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, + const u_char key[POLY1305_KEYLEN]) + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) + __attribute__((__bounded__(__buffer__, 2, 3))) + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); + +#endif /* POLY1305_H */ From loganaden at gmail.com Fri Nov 15 21:55:33 2013 From: loganaden at gmail.com (Loganaden Velvindron) Date: Fri, 15 Nov 2013 14:55:33 +0400 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Fri, Nov 15, 2013 at 2:03 PM, Damien Miller wrote: > On Thu, 14 Nov 2013, James Cloos wrote: > >> >>>>> "DM" == Damien Miller writes: >> >> DM> Here's a diff to implement ChaCha20+Poly1305 as an authenticated >> DM> encryption mode. It authenticates the packet length and payload, >> DM> and uses a separate ChaCh20 instance to encrypt the packet length >> DM> to preserve privacy of packet lengths* while avoiding any decryption >> DM> oracle for the main packet payload. >> >> Cool. >> >> I'd like to test it out, but for logistics reasons I'll have to do so on >> a linux box. Is anything written on what is needed to convert from the >> openbsd cvs tree to the portable tree? Or do you have a version of the >> patch applicable to the portable's cvs? > > Here's one that applies to portable OpenSSH. Also available at > http://www.mindrot.org/files/chachapoly1305_04_portable.diff What kind of test case are you expecting ? > > Index: Makefile.in > =================================================================== > RCS file: /var/cvs/openssh/Makefile.in,v > retrieving revision 1.344 > diff -u -p -r1.344 Makefile.in > --- Makefile.in 8 Nov 2013 13:17:41 -0000 1.344 > +++ Makefile.in 15 Nov 2013 00:08:29 -0000 > @@ -74,7 +74,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o > kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ > msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ > jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \ > - kexc25519.o kexc25519c.o > + kexc25519.o kexc25519c.o chacha.o chacha20poly1305aead.o \ > + poly1305-donna-unrolled.o > > SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ > sshconnect.o sshconnect1.o sshconnect2.o mux.o \ > Index: PROTOCOL > =================================================================== > RCS file: /var/cvs/openssh/PROTOCOL,v > retrieving revision 1.20 > diff -u -p -r1.20 PROTOCOL > --- PROTOCOL 17 Oct 2013 00:48:53 -0000 1.20 > +++ PROTOCOL 15 Nov 2013 00:08:29 -0000 > @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G > the exchanged MAC algorithms are ignored and there doesn't have to be > a matching MAC. > > +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption > + > +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 > +as described in PROTOCOL.chacha20poly1305. > + > 2. Connection protocol changes > > 2.1. connection: Channel write close extension "eow at openssh.com" > Index: PROTOCOL.chacha20poly1305 > =================================================================== > RCS file: PROTOCOL.chacha20poly1305 > diff -N PROTOCOL.chacha20poly1305 > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ PROTOCOL.chacha20poly1305 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,99 @@ > +This document describes the chacha20-poly1305 at openssh.com authenticated > +encryption cipher supported by OpenSSH. > + > +Background > +---------- > + > +ChaCha20 is a stream cipher designed by Daniel Bernstein and described > +in [1]. 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 stream output. > + > +Poly1305[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC > +that computes a 128 bit integrity tag given a message and a 256 bit key. > + > +The chacha20-poly1305 at openssh.com combines these two primitives into an > +autenticated encryption mode. The construction used is based on that > +proposed for TLS by Adam Langley in [3], but differs in the layout of > +data passed to the MAC and in the addition of encyption of the packet > +lengths. > + > +Negotiation > +----------- > + > +The chacha20-poly1305 at openssh.com offers both encryption and > +authentication. As such, no separate MAC is required. If the > +chacha20-poly1305 at openssh.com cipher is selected in key exchange, > +the offered MAC algorithms are ignored and no MAC is required to be > +negotiated. > + > +Detailed Construction > +--------------------- > + > +The chacha20-poly1305 at openssh.com cipher required 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 K_1 is a pure stream cipher that is used only > +to encrypt the 4 byte packet length field. The second instance, > +keyed by K_2, is used in conjunction with poly1305 to build an AEAD > +(Authenticated Encryption with Associated Data) that is used to encrypt > +and authenticate entire packet. > + > +Two separate cipher instances are used here so as to keep the packet > +lengths confidential but not create an oracle for the packet payload > +encryption by decrypting and using the packet length prior to checking > +the MAC. By using an independently-keyed cipher instance to encrypt the > +length, an active attacker seeking to exploit the packet input handling > +as a decryption oracle can learn nothing about the payload contents or > +its MAC (assuming key derivation is secure). > + > +The AEAD is constructed as follows: for each packet, generate a Poly1305 > +key by taking the first 256 bits of ChaCha20 stream output generated > +using K_2, an IV consisting of the packet sequence number encoded as an > +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of > +zero. The K_2 ChaCha20 block counter is then set to the little-endian > +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used > +for encryption of the packet payload. > + > +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 K_1 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 with the one appended to the packet and the packet > +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the > +encrypted length. Finally, calculate a MAC tag and append it. > + > +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 rekeying every 1GB of data > +sent or received. If this recommendation is followed, then > +chacha20-poly1305 at openssh.com requires no special handling in this area. > + > +References > +---------- > + > +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein > + http://cr.yp.to/chacha/chacha-20080128.pdf > + > +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein > + http://cr.yp.to/mac/poly1305-20050329.pdf > + > +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley > + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 > + > +$OpenBSD$ > + > Index: authfile.c > =================================================================== > RCS file: /var/cvs/openssh/authfile.c,v > retrieving revision 1.101 > diff -u -p -r1.101 authfile.c > --- authfile.c 1 Jun 2013 21:31:18 -0000 1.101 > +++ authfile.c 15 Nov 2013 00:08:29 -0000 > @@ -149,7 +149,7 @@ key_private_rsa1_to_blob(Key *key, Buffe > > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_ENCRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > @@ -473,7 +473,7 @@ key_parse_private_rsa1(Buffer *blob, con > /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_DECRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(©), buffer_len(©), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > Index: chacha.c > =================================================================== > RCS file: chacha.c > diff -N chacha.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.c 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,217 @@ > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > +#include > +#include "chacha.h" > + > +/* $OpenBSD$ */ > + > +typedef unsigned char u8; > +typedef unsigned int u32; > + > +typedef struct chacha_ctx chacha_ctx; > + > +#define U8C(v) (v##U) > +#define U32C(v) (v##U) > + > +#define U8V(v) ((u8)(v) & U8C(0xFF)) > +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) > + > +#define ROTL32(v, n) \ > + (U32V((v) << (n)) | ((v) >> (32 - (n)))) > + > +#define U8TO32_LITTLE(p) \ > + (((u32)((p)[0]) ) | \ > + ((u32)((p)[1]) << 8) | \ > + ((u32)((p)[2]) << 16) | \ > + ((u32)((p)[3]) << 24)) > + > +#define U32TO8_LITTLE(p, v) \ > + do { \ > + (p)[0] = U8V((v) ); \ > + (p)[1] = U8V((v) >> 8); \ > + (p)[2] = U8V((v) >> 16); \ > + (p)[3] = U8V((v) >> 24); \ > + } while (0) > + > +#define ROTATE(v,c) (ROTL32(v,c)) > +#define XOR(v,w) ((v) ^ (w)) > +#define PLUS(v,w) (U32V((v) + (w))) > +#define PLUSONE(v) (PLUS((v),1)) > + > +#define QUARTERROUND(a,b,c,d) \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); > + > +static const char sigma[16] = "expand 32-byte k"; > +static const char tau[16] = "expand 16-byte k"; > + > +void > +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) > +{ > + const char *constants; > + > + x->input[4] = U8TO32_LITTLE(k + 0); > + x->input[5] = U8TO32_LITTLE(k + 4); > + x->input[6] = U8TO32_LITTLE(k + 8); > + x->input[7] = U8TO32_LITTLE(k + 12); > + if (kbits == 256) { /* recommended */ > + k += 16; > + constants = sigma; > + } else { /* kbits == 128 */ > + constants = tau; > + } > + x->input[8] = U8TO32_LITTLE(k + 0); > + x->input[9] = U8TO32_LITTLE(k + 4); > + x->input[10] = U8TO32_LITTLE(k + 8); > + x->input[11] = U8TO32_LITTLE(k + 12); > + x->input[0] = U8TO32_LITTLE(constants + 0); > + x->input[1] = U8TO32_LITTLE(constants + 4); > + x->input[2] = U8TO32_LITTLE(constants + 8); > + x->input[3] = U8TO32_LITTLE(constants + 12); > +} > + > +void > +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) > +{ > + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); > + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); > + x->input[14] = U8TO32_LITTLE(iv + 0); > + x->input[15] = U8TO32_LITTLE(iv + 4); > +} > + > +void > +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) > +{ > + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; > + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; > + u8 *ctarget = NULL; > + u8 tmp[64]; > + u_int i; > + > + if (!bytes) return; > + > + j0 = x->input[0]; > + j1 = x->input[1]; > + j2 = x->input[2]; > + j3 = x->input[3]; > + j4 = x->input[4]; > + j5 = x->input[5]; > + j6 = x->input[6]; > + j7 = x->input[7]; > + j8 = x->input[8]; > + j9 = x->input[9]; > + j10 = x->input[10]; > + j11 = x->input[11]; > + j12 = x->input[12]; > + j13 = x->input[13]; > + j14 = x->input[14]; > + j15 = x->input[15]; > + > + for (;;) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) tmp[i] = m[i]; > + m = tmp; > + ctarget = c; > + c = tmp; > + } > + x0 = j0; > + x1 = j1; > + x2 = j2; > + x3 = j3; > + x4 = j4; > + x5 = j5; > + x6 = j6; > + x7 = j7; > + x8 = j8; > + x9 = j9; > + x10 = j10; > + x11 = j11; > + x12 = j12; > + x13 = j13; > + x14 = j14; > + x15 = j15; > + for (i = 20;i > 0;i -= 2) { > + QUARTERROUND( x0, x4, x8,x12) > + QUARTERROUND( x1, x5, x9,x13) > + QUARTERROUND( x2, x6,x10,x14) > + QUARTERROUND( x3, x7,x11,x15) > + QUARTERROUND( x0, x5,x10,x15) > + QUARTERROUND( x1, x6,x11,x12) > + QUARTERROUND( x2, x7, x8,x13) > + QUARTERROUND( x3, x4, x9,x14) > + } > + x0 = PLUS(x0,j0); > + x1 = PLUS(x1,j1); > + x2 = PLUS(x2,j2); > + x3 = PLUS(x3,j3); > + x4 = PLUS(x4,j4); > + x5 = PLUS(x5,j5); > + x6 = PLUS(x6,j6); > + x7 = PLUS(x7,j7); > + x8 = PLUS(x8,j8); > + x9 = PLUS(x9,j9); > + x10 = PLUS(x10,j10); > + x11 = PLUS(x11,j11); > + x12 = PLUS(x12,j12); > + x13 = PLUS(x13,j13); > + x14 = PLUS(x14,j14); > + x15 = PLUS(x15,j15); > + > + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); > + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); > + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); > + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); > + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); > + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); > + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); > + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); > + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); > + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); > + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); > + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); > + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); > + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); > + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); > + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); > + > + j12 = PLUSONE(j12); > + if (!j12) { > + j13 = PLUSONE(j13); > + /* stopping at 2^70 bytes per nonce is user's responsibility */ > + } > + > + U32TO8_LITTLE(c + 0,x0); > + U32TO8_LITTLE(c + 4,x1); > + U32TO8_LITTLE(c + 8,x2); > + U32TO8_LITTLE(c + 12,x3); > + U32TO8_LITTLE(c + 16,x4); > + U32TO8_LITTLE(c + 20,x5); > + U32TO8_LITTLE(c + 24,x6); > + U32TO8_LITTLE(c + 28,x7); > + U32TO8_LITTLE(c + 32,x8); > + U32TO8_LITTLE(c + 36,x9); > + U32TO8_LITTLE(c + 40,x10); > + U32TO8_LITTLE(c + 44,x11); > + U32TO8_LITTLE(c + 48,x12); > + U32TO8_LITTLE(c + 52,x13); > + U32TO8_LITTLE(c + 56,x14); > + U32TO8_LITTLE(c + 60,x15); > + > + if (bytes <= 64) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; > + } > + x->input[12] = j12; > + x->input[13] = j13; > + return; > + } > + bytes -= 64; > + c += 64; > + m += 64; > + } > +} > Index: chacha.h > =================================================================== > RCS file: chacha.h > diff -N chacha.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.h 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,35 @@ > +/* $OpenBSD$ */ > + > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > + > +#ifndef CHACHA_H > +#define CHACHA_H > + > +#include > + > +struct chacha_ctx { > + u_int input[16]; > +}; > + > +#define CHACHA_MINKEYLEN 16 > +#define CHACHA_NONCELEN 8 > +#define CHACHA_CTRLEN 8 > +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) > +#define CHACHA_BLOCKLEN 64 > + > +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); > +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) > + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); > +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, > + u_char *c, u_int bytes) > + __attribute__((__bounded__(__buffer__, 2, 4))) > + __attribute__((__bounded__(__buffer__, 3, 4))); > + > +#endif /* CHACHA_H */ > + > Index: chacha20poly1305aead.c > =================================================================== > RCS file: chacha20poly1305aead.c > diff -N chacha20poly1305aead.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.c 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,111 @@ > +/* > + * Copyright (c) 2013 Damien Miller > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include > +#include /* needed for misc.h */ > +#include /* needed for log.h */ > +#include > +#include /* needed for misc.h */ > + > +#include "log.h" > +#include "misc.h" > +#include "chacha20poly1305aead.h" > + > +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, > + const u_char *key, u_int keylen) > +{ > + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ > + fatal("%s: invalid keylen %u", __func__, keylen); > + chacha_keysetup(&ctx->main_ctx, key, 256); > + chacha_keysetup(&ctx->header_ctx, key + 32, 256); > +} > + > +/* > + * cp_aead_crypt() operates as following: > + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. > + * Theses bytes are treated as additional authenticated data. > + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. > + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the > + * authentication tag. > + * This tag is written on encryption and verified on decryption. > + * Both 'aadlen' and 'authlen' can be set to 0. > + */ > +int > +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, > + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) > +{ > + u_char seqbuf[8]; > + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ > + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; > + int r = -1; > + > + /* > + * Run ChaCha20 once to generate the Poly1305 key. The IV is the > + * packet sequence number. > + */ > + bzero(poly_key, sizeof(poly_key)); > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->main_ctx, > + poly_key, poly_key, sizeof(poly_key)); > + /* Set Chacha's block counter to 1 */ > + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); > + > + /* If decrypting, check tag before anything else */ > + if (!do_encrypt) { > + const u_char *tag = src + aadlen + len; > + > + poly1305_auth(expected_tag, src, aadlen + len, poly_key); > + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) > + goto out; > + } > + /* Crypt additional data */ > + if (aadlen) { > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); > + } > + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, > + dest + aadlen, len); > + > + /* If encrypting, calculate and append tag */ > + if (do_encrypt) { > + poly1305_auth(dest + aadlen + len, dest, aadlen + len, > + poly_key); > + } > + r = 0; > + > + out: > + bzero(expected_tag, sizeof(expected_tag)); > + bzero(seqbuf, sizeof(seqbuf)); > + bzero(poly_key, sizeof(poly_key)); > + return r; > +} > + > +int > +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > +{ > + u_char buf[4], seqbuf[8]; > + > + if (len < 4) > + return -1; /* Insufficient length */ > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); > + *plenp = get_u32(buf); > + return 0; > +} > + > Index: chacha20poly1305aead.h > =================================================================== > RCS file: chacha20poly1305aead.h > diff -N chacha20poly1305aead.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.h 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,41 @@ > +/* $OpenBSD$ */ > + > +/* > + * Copyright (c) Damien Miller 2013 > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > +#ifndef CHACHA_POLY_AEAD_H > +#define CHACHA_POLY_AEAD_H > + > +#include > +#include "chacha.h" > +#include "poly1305-donna-unrolled.h" > + > +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ > + > +struct chacha_poly_aead_ctx { > + struct chacha_ctx main_ctx, header_ctx; > +}; > + > +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, > + const u_char *key, u_int keylen) > + __attribute__((__bounded__(__buffer__, 2, 3))); > +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, > + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, > + int do_encrypt); > +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > + __attribute__((__bounded__(__buffer__, 4, 5))); > + > +#endif /* CHACHA_POLY_AEAD_H */ > Index: cipher.c > =================================================================== > RCS file: /var/cvs/openssh/cipher.c,v > retrieving revision 1.97 > diff -u -p -r1.97 cipher.c > --- cipher.c 8 Nov 2013 01:16:50 -0000 1.97 > +++ cipher.c 15 Nov 2013 00:08:29 -0000 > @@ -43,9 +43,11 @@ > > #include > #include > +#include > > #include "xmalloc.h" > #include "log.h" > +#include "misc.h" > #include "cipher.h" > > /* compatibility with old or broken OpenSSL versions */ > @@ -63,7 +65,9 @@ struct Cipher { > u_int iv_len; /* defaults to block_size */ > u_int auth_len; > u_int discard_len; > - u_int cbc_mode; > + u_int flags; > +#define CFLAG_CBC (1<<0) > +#define CFLAG_CP_AEAD (1<<1) > const EVP_CIPHER *(*evptype)(void); > }; > > @@ -95,6 +99,8 @@ static const struct Cipher ciphers[] = { > { "aes256-gcm at openssh.com", > SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, > #endif > + { "chacha20-poly1305 at openssh.com", > + SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, > { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } > }; > > @@ -142,7 +148,12 @@ cipher_authlen(const Cipher *c) > u_int > cipher_ivlen(const Cipher *c) > { > - return (c->iv_len ? c->iv_len : c->block_size); > + /* > + * Default is cipher block size, except for chacha20+poly1305 that > + * needs no IV. XXX make iv_len == -1 default? > + */ > + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? > + c->iv_len : c->block_size; > } > > u_int > @@ -154,7 +165,7 @@ cipher_get_number(const Cipher *c) > u_int > cipher_is_cbc(const Cipher *c) > { > - return (c->cbc_mode); > + return (c->flags & CFLAG_CBC) != 0; > } > > u_int > @@ -274,8 +285,11 @@ cipher_init(CipherContext *cc, const Cip > ivlen, cipher->name); > cc->cipher = cipher; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + cp_aead_init(&cc->cp_ctx, key, keylen); > + return; > + } > type = (*cipher->evptype)(); > - > EVP_CIPHER_CTX_init(&cc->evp); > #ifdef SSH_OLD_EVP > if (type->key_len > 0 && type->key_len != keylen) { > @@ -330,9 +344,15 @@ cipher_init(CipherContext *cc, const Cip > * Both 'aadlen' and 'authlen' can be set to 0. > */ > void > -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, > +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, > u_int len, u_int aadlen, u_int authlen) > { > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, > + authlen, cc->encrypt) != 0) > + fatal("Decryption integrity check failed"); > + return; > + } > if (authlen) { > u_char lastiv[1]; > > @@ -374,10 +394,29 @@ cipher_crypt(CipherContext *cc, u_char * > } > } > > +/* > + * Extract the packet length for an AEAD cipher, including any decryption > + * necessary beforehand. > + */ > +int > +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, > + const u_char *cp, u_int len) > +{ > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, > + cp, len); > + if (len < 4) > + return -1; > + *plenp = get_u32(cp); > + return 0; > +} > + > void > cipher_cleanup(CipherContext *cc) > { > - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); > + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); > } > > @@ -417,6 +456,8 @@ cipher_get_keyiv_len(const CipherContext > > if (c->number == SSH_CIPHER_3DES) > ivlen = 24; > + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + ivlen = 0; > else > ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); > return (ivlen); > @@ -428,6 +469,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch > const Cipher *c = cc->cipher; > int evplen; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (len != 0) > + fatal("%s: wrong iv length %d != %d", __func__, len, 0); > + return; > + } > + > switch (c->number) { > case SSH_CIPHER_SSH2: > case SSH_CIPHER_DES: > @@ -463,6 +510,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch > { > const Cipher *c = cc->cipher; > int evplen = 0; > + > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return; > > switch (c->number) { > case SSH_CIPHER_SSH2: > Index: cipher.h > =================================================================== > RCS file: /var/cvs/openssh/cipher.h,v > retrieving revision 1.37 > diff -u -p -r1.37 cipher.h > --- cipher.h 8 Nov 2013 01:16:50 -0000 1.37 > +++ cipher.h 15 Nov 2013 00:08:29 -0000 > @@ -38,6 +38,8 @@ > #define CIPHER_H > > #include > +#include "chacha20poly1305aead.h" > + > /* > * Cipher types for SSH-1. New types can be added, but old types should not > * be removed for compatibility. The maximum allowed value is 31. > @@ -65,7 +67,9 @@ struct Cipher; > struct CipherContext { > int plaintext; > int encrypt; > + int is_cp_aead; > EVP_CIPHER_CTX evp; > + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ > const Cipher *cipher; > }; > > @@ -78,8 +82,10 @@ int ciphers_valid(const char *); > char *cipher_alg_list(char); > void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, > const u_char *, u_int, int); > -void cipher_crypt(CipherContext *, u_char *, const u_char *, > +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, > u_int, u_int, u_int); > +int cipher_aead_get_length(CipherContext *, u_int *, u_int, > + const u_char *, u_int); > void cipher_cleanup(CipherContext *); > void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); > u_int cipher_blocksize(const Cipher *); > Index: myproposal.h > =================================================================== > RCS file: /var/cvs/openssh/myproposal.h,v > retrieving revision 1.43 > diff -u -p -r1.43 myproposal.h > --- myproposal.h 9 Nov 2013 07:39:25 -0000 1.43 > +++ myproposal.h 15 Nov 2013 00:08:30 -0000 > @@ -104,6 +104,7 @@ > "aes128-ctr,aes192-ctr,aes256-ctr," \ > "arcfour256,arcfour128," \ > AESGCM_CIPHER_MODES \ > + "chacha20-poly1305 at openssh.com," \ > "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ > "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" > > Index: packet.c > =================================================================== > RCS file: /var/cvs/openssh/packet.c,v > retrieving revision 1.196 > diff -u -p -r1.196 packet.c > --- packet.c 8 Nov 2013 01:19:57 -0000 1.196 > +++ packet.c 15 Nov 2013 00:08:30 -0000 > @@ -713,7 +713,7 @@ packet_send1(void) > buffer_append(&active_state->output, buf, 4); > cp = buffer_append_space(&active_state->output, > buffer_len(&active_state->outgoing_packet)); > - cipher_crypt(&active_state->send_context, cp, > + cipher_crypt(&active_state->send_context, 0, cp, > buffer_ptr(&active_state->outgoing_packet), > buffer_len(&active_state->outgoing_packet), 0, 0); > > @@ -946,8 +946,8 @@ packet_send2_wrapped(void) > } > /* encrypt packet and append to output buffer. */ > cp = buffer_append_space(&active_state->output, len + authlen); > - cipher_crypt(&active_state->send_context, cp, > - buffer_ptr(&active_state->outgoing_packet), > + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, > + cp, buffer_ptr(&active_state->outgoing_packet), > len - aadlen, aadlen, authlen); > /* append unencrypted MAC */ > if (mac && mac->enabled) { > @@ -1208,7 +1208,7 @@ packet_read_poll1(void) > /* Decrypt data to incoming_packet. */ > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, padded_len); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, 0, cp, > buffer_ptr(&active_state->input), padded_len, 0, 0); > > buffer_consume(&active_state->input, padded_len); > @@ -1279,10 +1279,12 @@ packet_read_poll2(u_int32_t *seqnr_p) > aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; > > if (aadlen && active_state->packlen == 0) { > - if (buffer_len(&active_state->input) < 4) > + if (cipher_aead_get_length(&active_state->receive_context, > + &active_state->packlen, > + active_state->p_read.seqnr, > + buffer_ptr(&active_state->input), > + buffer_len(&active_state->input)) != 0) > return SSH_MSG_NONE; > - cp = buffer_ptr(&active_state->input); > - active_state->packlen = get_u32(cp); > if (active_state->packlen < 1 + 4 || > active_state->packlen > PACKET_MAX_SIZE) { > #ifdef PACKET_DEBUG > @@ -1302,7 +1304,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, > block_size); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), block_size, 0, 0); > cp = buffer_ptr(&active_state->incoming_packet); > active_state->packlen = get_u32(cp); > @@ -1357,7 +1360,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > macbuf = mac_compute(mac, active_state->p_read.seqnr, > buffer_ptr(&active_state->input), aadlen + need); > cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), need, aadlen, authlen); > buffer_consume(&active_state->input, aadlen + need + authlen); > /* > Index: poly1305-donna-unrolled.c > =================================================================== > RCS file: poly1305-donna-unrolled.c > diff -N poly1305-donna-unrolled.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.c 15 Nov 2013 00:08:30 -0000 > @@ -0,0 +1,154 @@ > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#include > +#include > + > +#include "poly1305-donna-unrolled.h" > + > +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) > + > +#define U8TO32_LE(p) \ > + (((uint32_t)((p)[0])) | \ > + ((uint32_t)((p)[1]) << 8) | \ > + ((uint32_t)((p)[2]) << 16) | \ > + ((uint32_t)((p)[3]) << 24)) > + > +#define U32TO8_LE(p, v) \ > + do { \ > + (p)[0] = (uint8_t)((v)); \ > + (p)[1] = (uint8_t)((v) >> 8); \ > + (p)[2] = (uint8_t)((v) >> 16); \ > + (p)[3] = (uint8_t)((v) >> 24); \ > + } while (0) > + > +void > +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { > + uint32_t t0,t1,t2,t3; > + uint32_t h0,h1,h2,h3,h4; > + uint32_t r0,r1,r2,r3,r4; > + uint32_t s1,s2,s3,s4; > + uint32_t b, nb; > + size_t j; > + uint64_t t[5]; > + uint64_t f0,f1,f2,f3; > + uint32_t g0,g1,g2,g3,g4; > + uint64_t c; > + unsigned char mp[16]; > + > + /* clamp key */ > + t0 = U8TO32_LE(key+0); > + t1 = U8TO32_LE(key+4); > + t2 = U8TO32_LE(key+8); > + t3 = U8TO32_LE(key+12); > + > + /* precompute multipliers */ > + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; > + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; > + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; > + r3 = t2 & 0x3f03fff; t3 >>= 8; > + r4 = t3 & 0x00fffff; > + > + s1 = r1 * 5; > + s2 = r2 * 5; > + s3 = r3 * 5; > + s4 = r4 * 5; > + > + /* init state */ > + h0 = 0; > + h1 = 0; > + h2 = 0; > + h3 = 0; > + h4 = 0; > + > + /* full blocks */ > + if (inlen < 16) goto poly1305_donna_atmost15bytes; > +poly1305_donna_16bytes: > + m += 16; > + inlen -= 16; > + > + t0 = U8TO32_LE(m-16); > + t1 = U8TO32_LE(m-12); > + t2 = U8TO32_LE(m-8); > + t3 = U8TO32_LE(m-4); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8) | (1 << 24); > + > + > +poly1305_donna_mul: > + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); > + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); > + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); > + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); > + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); > + > + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); > + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); > + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); > + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); > + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); > + h0 += b * 5; > + > + if (inlen >= 16) goto poly1305_donna_16bytes; > + > + /* final bytes */ > +poly1305_donna_atmost15bytes: > + if (!inlen) goto poly1305_donna_finish; > + > + for (j = 0; j < inlen; j++) mp[j] = m[j]; > + mp[j++] = 1; > + for (; j < 16; j++) mp[j] = 0; > + inlen = 0; > + > + t0 = U8TO32_LE(mp+0); > + t1 = U8TO32_LE(mp+4); > + t2 = U8TO32_LE(mp+8); > + t3 = U8TO32_LE(mp+12); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8); > + > + goto poly1305_donna_mul; > + > +poly1305_donna_finish: > + b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; > + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; > + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; > + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; > + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; > + > + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; > + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; > + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; > + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; > + g4 = h4 + b - (1 << 26); > + > + b = (g4 >> 31) - 1; > + nb = ~b; > + h0 = (h0 & nb) | (g0 & b); > + h1 = (h1 & nb) | (g1 & b); > + h2 = (h2 & nb) | (g2 & b); > + h3 = (h3 & nb) | (g3 & b); > + h4 = (h4 & nb) | (g4 & b); > + > + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); > + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); > + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); > + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); > + > + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); > + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); > + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); > + U32TO8_LE(&out[12], f3); > +} > Index: poly1305-donna-unrolled.h > =================================================================== > RCS file: poly1305-donna-unrolled.h > diff -N poly1305-donna-unrolled.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.h 15 Nov 2013 00:08:30 -0000 > @@ -0,0 +1,22 @@ > +/* $OpenBSD$ */ > + > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#ifndef POLY1305_H > +#define POLY1305_H > + > +#include > + > +#define POLY1305_KEYLEN 32 > +#define POLY1305_TAGLEN 16 > + > +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, > + const u_char key[POLY1305_KEYLEN]) > + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) > + __attribute__((__bounded__(__buffer__, 2, 3))) > + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); > + > +#endif /* POLY1305_H */ > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- This message is strictly personal and the opinions expressed do not represent those of my employers, either past or present. From loganaden at gmail.com Sat Nov 16 02:48:44 2013 From: loganaden at gmail.com (Loganaden Velvindron) Date: Fri, 15 Nov 2013 19:48:44 +0400 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Fri, Nov 15, 2013 at 2:55 PM, Loganaden Velvindron wrote: > On Fri, Nov 15, 2013 at 2:03 PM, Damien Miller wrote: >> On Thu, 14 Nov 2013, James Cloos wrote: >> >>> >>>>> "DM" == Damien Miller writes: >>> >>> DM> Here's a diff to implement ChaCha20+Poly1305 as an authenticated >>> DM> encryption mode. It authenticates the packet length and payload, >>> DM> and uses a separate ChaCh20 instance to encrypt the packet length >>> DM> to preserve privacy of packet lengths* while avoiding any decryption >>> DM> oracle for the main packet payload. >>> >>> Cool. >>> >>> I'd like to test it out, but for logistics reasons I'll have to do so on >>> a linux box. Is anything written on what is needed to convert from the >>> openbsd cvs tree to the portable tree? Or do you have a version of the >>> patch applicable to the portable's cvs? >> >> Here's one that applies to portable OpenSSH. Also available at >> http://www.mindrot.org/files/chachapoly1305_04_portable.diff > > What kind of test case are you expecting ? An include file seems to be missing for chacha20poly1305aead.c:72:3: warning: implicit declaration of function ?timingsafe_bcmp? [-Wimplicit-function-declaration] --- chacha20poly1305aead.c.orig 2013-11-15 19:48:01.977031397 +0400 +++ chacha20poly1305aead.c 2013-11-15 19:44:16.359912632 +0400 @@ -23,6 +23,7 @@ #include "log.h" #include "misc.h" #include "chacha20poly1305aead.h" +#include "openbsd-compat/openbsd-compat.h" void cp_aead_init(struct chacha_poly_aead_ctx *ctx, const u_char *key, u_int keylen) > > >> >> Index: Makefile.in >> =================================================================== >> RCS file: /var/cvs/openssh/Makefile.in,v >> retrieving revision 1.344 >> diff -u -p -r1.344 Makefile.in >> --- Makefile.in 8 Nov 2013 13:17:41 -0000 1.344 >> +++ Makefile.in 15 Nov 2013 00:08:29 -0000 >> @@ -74,7 +74,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o >> kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ >> msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ >> jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \ >> - kexc25519.o kexc25519c.o >> + kexc25519.o kexc25519c.o chacha.o chacha20poly1305aead.o \ >> + poly1305-donna-unrolled.o >> >> SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ >> sshconnect.o sshconnect1.o sshconnect2.o mux.o \ >> Index: PROTOCOL >> =================================================================== >> RCS file: /var/cvs/openssh/PROTOCOL,v >> retrieving revision 1.20 >> diff -u -p -r1.20 PROTOCOL >> --- PROTOCOL 17 Oct 2013 00:48:53 -0000 1.20 >> +++ PROTOCOL 15 Nov 2013 00:08:29 -0000 >> @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G >> the exchanged MAC algorithms are ignored and there doesn't have to be >> a matching MAC. >> >> +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption >> + >> +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 >> +as described in PROTOCOL.chacha20poly1305. >> + >> 2. Connection protocol changes >> >> 2.1. connection: Channel write close extension "eow at openssh.com" >> Index: PROTOCOL.chacha20poly1305 >> =================================================================== >> RCS file: PROTOCOL.chacha20poly1305 >> diff -N PROTOCOL.chacha20poly1305 >> --- /dev/null 1 Jan 1970 00:00:00 -0000 >> +++ PROTOCOL.chacha20poly1305 15 Nov 2013 00:08:29 -0000 >> @@ -0,0 +1,99 @@ >> +This document describes the chacha20-poly1305 at openssh.com authenticated >> +encryption cipher supported by OpenSSH. >> + >> +Background >> +---------- >> + >> +ChaCha20 is a stream cipher designed by Daniel Bernstein and described >> +in [1]. 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 stream output. >> + >> +Poly1305[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC >> +that computes a 128 bit integrity tag given a message and a 256 bit key. >> + >> +The chacha20-poly1305 at openssh.com combines these two primitives into an >> +autenticated encryption mode. The construction used is based on that >> +proposed for TLS by Adam Langley in [3], but differs in the layout of >> +data passed to the MAC and in the addition of encyption of the packet >> +lengths. >> + >> +Negotiation >> +----------- >> + >> +The chacha20-poly1305 at openssh.com offers both encryption and >> +authentication. As such, no separate MAC is required. If the >> +chacha20-poly1305 at openssh.com cipher is selected in key exchange, >> +the offered MAC algorithms are ignored and no MAC is required to be >> +negotiated. >> + >> +Detailed Construction >> +--------------------- >> + >> +The chacha20-poly1305 at openssh.com cipher required 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 K_1 is a pure stream cipher that is used only >> +to encrypt the 4 byte packet length field. The second instance, >> +keyed by K_2, is used in conjunction with poly1305 to build an AEAD >> +(Authenticated Encryption with Associated Data) that is used to encrypt >> +and authenticate entire packet. >> + >> +Two separate cipher instances are used here so as to keep the packet >> +lengths confidential but not create an oracle for the packet payload >> +encryption by decrypting and using the packet length prior to checking >> +the MAC. By using an independently-keyed cipher instance to encrypt the >> +length, an active attacker seeking to exploit the packet input handling >> +as a decryption oracle can learn nothing about the payload contents or >> +its MAC (assuming key derivation is secure). >> + >> +The AEAD is constructed as follows: for each packet, generate a Poly1305 >> +key by taking the first 256 bits of ChaCha20 stream output generated >> +using K_2, an IV consisting of the packet sequence number encoded as an >> +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of >> +zero. The K_2 ChaCha20 block counter is then set to the little-endian >> +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used >> +for encryption of the packet payload. >> + >> +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 K_1 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 with the one appended to the packet and the packet >> +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the >> +encrypted length. Finally, calculate a MAC tag and append it. >> + >> +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 rekeying every 1GB of data >> +sent or received. If this recommendation is followed, then >> +chacha20-poly1305 at openssh.com requires no special handling in this area. >> + >> +References >> +---------- >> + >> +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein >> + http://cr.yp.to/chacha/chacha-20080128.pdf >> + >> +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein >> + http://cr.yp.to/mac/poly1305-20050329.pdf >> + >> +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley >> + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 >> + >> +$OpenBSD$ >> + >> Index: authfile.c >> =================================================================== >> RCS file: /var/cvs/openssh/authfile.c,v >> retrieving revision 1.101 >> diff -u -p -r1.101 authfile.c >> --- authfile.c 1 Jun 2013 21:31:18 -0000 1.101 >> +++ authfile.c 15 Nov 2013 00:08:29 -0000 >> @@ -149,7 +149,7 @@ key_private_rsa1_to_blob(Key *key, Buffe >> >> cipher_set_key_string(&ciphercontext, cipher, passphrase, >> CIPHER_ENCRYPT); >> - cipher_crypt(&ciphercontext, cp, >> + cipher_crypt(&ciphercontext, 0, cp, >> buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); >> cipher_cleanup(&ciphercontext); >> memset(&ciphercontext, 0, sizeof(ciphercontext)); >> @@ -473,7 +473,7 @@ key_parse_private_rsa1(Buffer *blob, con >> /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ >> cipher_set_key_string(&ciphercontext, cipher, passphrase, >> CIPHER_DECRYPT); >> - cipher_crypt(&ciphercontext, cp, >> + cipher_crypt(&ciphercontext, 0, cp, >> buffer_ptr(©), buffer_len(©), 0, 0); >> cipher_cleanup(&ciphercontext); >> memset(&ciphercontext, 0, sizeof(ciphercontext)); >> Index: chacha.c >> =================================================================== >> RCS file: chacha.c >> diff -N chacha.c >> --- /dev/null 1 Jan 1970 00:00:00 -0000 >> +++ chacha.c 15 Nov 2013 00:08:29 -0000 >> @@ -0,0 +1,217 @@ >> +/* >> +chacha-merged.c version 20080118 >> +D. J. Bernstein >> +Public domain. >> +*/ >> +#include >> +#include "chacha.h" >> + >> +/* $OpenBSD$ */ >> + >> +typedef unsigned char u8; >> +typedef unsigned int u32; >> + >> +typedef struct chacha_ctx chacha_ctx; >> + >> +#define U8C(v) (v##U) >> +#define U32C(v) (v##U) >> + >> +#define U8V(v) ((u8)(v) & U8C(0xFF)) >> +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) >> + >> +#define ROTL32(v, n) \ >> + (U32V((v) << (n)) | ((v) >> (32 - (n)))) >> + >> +#define U8TO32_LITTLE(p) \ >> + (((u32)((p)[0]) ) | \ >> + ((u32)((p)[1]) << 8) | \ >> + ((u32)((p)[2]) << 16) | \ >> + ((u32)((p)[3]) << 24)) >> + >> +#define U32TO8_LITTLE(p, v) \ >> + do { \ >> + (p)[0] = U8V((v) ); \ >> + (p)[1] = U8V((v) >> 8); \ >> + (p)[2] = U8V((v) >> 16); \ >> + (p)[3] = U8V((v) >> 24); \ >> + } while (0) >> + >> +#define ROTATE(v,c) (ROTL32(v,c)) >> +#define XOR(v,w) ((v) ^ (w)) >> +#define PLUS(v,w) (U32V((v) + (w))) >> +#define PLUSONE(v) (PLUS((v),1)) >> + >> +#define QUARTERROUND(a,b,c,d) \ >> + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ >> + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ >> + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ >> + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); >> + >> +static const char sigma[16] = "expand 32-byte k"; >> +static const char tau[16] = "expand 16-byte k"; >> + >> +void >> +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) >> +{ >> + const char *constants; >> + >> + x->input[4] = U8TO32_LITTLE(k + 0); >> + x->input[5] = U8TO32_LITTLE(k + 4); >> + x->input[6] = U8TO32_LITTLE(k + 8); >> + x->input[7] = U8TO32_LITTLE(k + 12); >> + if (kbits == 256) { /* recommended */ >> + k += 16; >> + constants = sigma; >> + } else { /* kbits == 128 */ >> + constants = tau; >> + } >> + x->input[8] = U8TO32_LITTLE(k + 0); >> + x->input[9] = U8TO32_LITTLE(k + 4); >> + x->input[10] = U8TO32_LITTLE(k + 8); >> + x->input[11] = U8TO32_LITTLE(k + 12); >> + x->input[0] = U8TO32_LITTLE(constants + 0); >> + x->input[1] = U8TO32_LITTLE(constants + 4); >> + x->input[2] = U8TO32_LITTLE(constants + 8); >> + x->input[3] = U8TO32_LITTLE(constants + 12); >> +} >> + >> +void >> +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) >> +{ >> + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); >> + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); >> + x->input[14] = U8TO32_LITTLE(iv + 0); >> + x->input[15] = U8TO32_LITTLE(iv + 4); >> +} >> + >> +void >> +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) >> +{ >> + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; >> + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; >> + u8 *ctarget = NULL; >> + u8 tmp[64]; >> + u_int i; >> + >> + if (!bytes) return; >> + >> + j0 = x->input[0]; >> + j1 = x->input[1]; >> + j2 = x->input[2]; >> + j3 = x->input[3]; >> + j4 = x->input[4]; >> + j5 = x->input[5]; >> + j6 = x->input[6]; >> + j7 = x->input[7]; >> + j8 = x->input[8]; >> + j9 = x->input[9]; >> + j10 = x->input[10]; >> + j11 = x->input[11]; >> + j12 = x->input[12]; >> + j13 = x->input[13]; >> + j14 = x->input[14]; >> + j15 = x->input[15]; >> + >> + for (;;) { >> + if (bytes < 64) { >> + for (i = 0;i < bytes;++i) tmp[i] = m[i]; >> + m = tmp; >> + ctarget = c; >> + c = tmp; >> + } >> + x0 = j0; >> + x1 = j1; >> + x2 = j2; >> + x3 = j3; >> + x4 = j4; >> + x5 = j5; >> + x6 = j6; >> + x7 = j7; >> + x8 = j8; >> + x9 = j9; >> + x10 = j10; >> + x11 = j11; >> + x12 = j12; >> + x13 = j13; >> + x14 = j14; >> + x15 = j15; >> + for (i = 20;i > 0;i -= 2) { >> + QUARTERROUND( x0, x4, x8,x12) >> + QUARTERROUND( x1, x5, x9,x13) >> + QUARTERROUND( x2, x6,x10,x14) >> + QUARTERROUND( x3, x7,x11,x15) >> + QUARTERROUND( x0, x5,x10,x15) >> + QUARTERROUND( x1, x6,x11,x12) >> + QUARTERROUND( x2, x7, x8,x13) >> + QUARTERROUND( x3, x4, x9,x14) >> + } >> + x0 = PLUS(x0,j0); >> + x1 = PLUS(x1,j1); >> + x2 = PLUS(x2,j2); >> + x3 = PLUS(x3,j3); >> + x4 = PLUS(x4,j4); >> + x5 = PLUS(x5,j5); >> + x6 = PLUS(x6,j6); >> + x7 = PLUS(x7,j7); >> + x8 = PLUS(x8,j8); >> + x9 = PLUS(x9,j9); >> + x10 = PLUS(x10,j10); >> + x11 = PLUS(x11,j11); >> + x12 = PLUS(x12,j12); >> + x13 = PLUS(x13,j13); >> + x14 = PLUS(x14,j14); >> + x15 = PLUS(x15,j15); >> + >> + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); >> + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); >> + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); >> + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); >> + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); >> + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); >> + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); >> + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); >> + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); >> + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); >> + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); >> + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); >> + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); >> + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); >> + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); >> + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); >> + >> + j12 = PLUSONE(j12); >> + if (!j12) { >> + j13 = PLUSONE(j13); >> + /* stopping at 2^70 bytes per nonce is user's responsibility */ >> + } >> + >> + U32TO8_LITTLE(c + 0,x0); >> + U32TO8_LITTLE(c + 4,x1); >> + U32TO8_LITTLE(c + 8,x2); >> + U32TO8_LITTLE(c + 12,x3); >> + U32TO8_LITTLE(c + 16,x4); >> + U32TO8_LITTLE(c + 20,x5); >> + U32TO8_LITTLE(c + 24,x6); >> + U32TO8_LITTLE(c + 28,x7); >> + U32TO8_LITTLE(c + 32,x8); >> + U32TO8_LITTLE(c + 36,x9); >> + U32TO8_LITTLE(c + 40,x10); >> + U32TO8_LITTLE(c + 44,x11); >> + U32TO8_LITTLE(c + 48,x12); >> + U32TO8_LITTLE(c + 52,x13); >> + U32TO8_LITTLE(c + 56,x14); >> + U32TO8_LITTLE(c + 60,x15); >> + >> + if (bytes <= 64) { >> + if (bytes < 64) { >> + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; >> + } >> + x->input[12] = j12; >> + x->input[13] = j13; >> + return; >> + } >> + bytes -= 64; >> + c += 64; >> + m += 64; >> + } >> +} >> Index: chacha.h >> =================================================================== >> RCS file: chacha.h >> diff -N chacha.h >> --- /dev/null 1 Jan 1970 00:00:00 -0000 >> +++ chacha.h 15 Nov 2013 00:08:29 -0000 >> @@ -0,0 +1,35 @@ >> +/* $OpenBSD$ */ >> + >> +/* >> +chacha-merged.c version 20080118 >> +D. J. Bernstein >> +Public domain. >> +*/ >> + >> +#ifndef CHACHA_H >> +#define CHACHA_H >> + >> +#include >> + >> +struct chacha_ctx { >> + u_int input[16]; >> +}; >> + >> +#define CHACHA_MINKEYLEN 16 >> +#define CHACHA_NONCELEN 8 >> +#define CHACHA_CTRLEN 8 >> +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) >> +#define CHACHA_BLOCKLEN 64 >> + >> +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) >> + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); >> +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) >> + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) >> + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); >> +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, >> + u_char *c, u_int bytes) >> + __attribute__((__bounded__(__buffer__, 2, 4))) >> + __attribute__((__bounded__(__buffer__, 3, 4))); >> + >> +#endif /* CHACHA_H */ >> + >> Index: chacha20poly1305aead.c >> =================================================================== >> RCS file: chacha20poly1305aead.c >> diff -N chacha20poly1305aead.c >> --- /dev/null 1 Jan 1970 00:00:00 -0000 >> +++ chacha20poly1305aead.c 15 Nov 2013 00:08:29 -0000 >> @@ -0,0 +1,111 @@ >> +/* >> + * Copyright (c) 2013 Damien Miller >> + * >> + * Permission to use, copy, modify, and distribute this software for any >> + * purpose with or without fee is hereby granted, provided that the above >> + * copyright notice and this permission notice appear in all copies. >> + * >> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES >> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF >> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR >> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES >> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN >> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF >> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. >> + */ >> + >> +#include >> +#include /* needed for misc.h */ >> +#include /* needed for log.h */ >> +#include >> +#include /* needed for misc.h */ >> + >> +#include "log.h" >> +#include "misc.h" >> +#include "chacha20poly1305aead.h" >> + >> +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, >> + const u_char *key, u_int keylen) >> +{ >> + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ >> + fatal("%s: invalid keylen %u", __func__, keylen); >> + chacha_keysetup(&ctx->main_ctx, key, 256); >> + chacha_keysetup(&ctx->header_ctx, key + 32, 256); >> +} >> + >> +/* >> + * cp_aead_crypt() operates as following: >> + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. >> + * Theses bytes are treated as additional authenticated data. >> + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. >> + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the >> + * authentication tag. >> + * This tag is written on encryption and verified on decryption. >> + * Both 'aadlen' and 'authlen' can be set to 0. >> + */ >> +int >> +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, >> + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) >> +{ >> + u_char seqbuf[8]; >> + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ >> + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; >> + int r = -1; >> + >> + /* >> + * Run ChaCha20 once to generate the Poly1305 key. The IV is the >> + * packet sequence number. >> + */ >> + bzero(poly_key, sizeof(poly_key)); >> + put_u64(seqbuf, seqnr); >> + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); >> + chacha_encrypt_bytes(&ctx->main_ctx, >> + poly_key, poly_key, sizeof(poly_key)); >> + /* Set Chacha's block counter to 1 */ >> + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); >> + >> + /* If decrypting, check tag before anything else */ >> + if (!do_encrypt) { >> + const u_char *tag = src + aadlen + len; >> + >> + poly1305_auth(expected_tag, src, aadlen + len, poly_key); >> + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) >> + goto out; >> + } >> + /* Crypt additional data */ >> + if (aadlen) { >> + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); >> + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); >> + } >> + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, >> + dest + aadlen, len); >> + >> + /* If encrypting, calculate and append tag */ >> + if (do_encrypt) { >> + poly1305_auth(dest + aadlen + len, dest, aadlen + len, >> + poly_key); >> + } >> + r = 0; >> + >> + out: >> + bzero(expected_tag, sizeof(expected_tag)); >> + bzero(seqbuf, sizeof(seqbuf)); >> + bzero(poly_key, sizeof(poly_key)); >> + return r; >> +} >> + >> +int >> +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, >> + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) >> +{ >> + u_char buf[4], seqbuf[8]; >> + >> + if (len < 4) >> + return -1; /* Insufficient length */ >> + put_u64(seqbuf, seqnr); >> + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); >> + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); >> + *plenp = get_u32(buf); >> + return 0; >> +} >> + >> Index: chacha20poly1305aead.h >> =================================================================== >> RCS file: chacha20poly1305aead.h >> diff -N chacha20poly1305aead.h >> --- /dev/null 1 Jan 1970 00:00:00 -0000 >> +++ chacha20poly1305aead.h 15 Nov 2013 00:08:29 -0000 >> @@ -0,0 +1,41 @@ >> +/* $OpenBSD$ */ >> + >> +/* >> + * Copyright (c) Damien Miller 2013 >> + * >> + * Permission to use, copy, modify, and distribute this software for any >> + * purpose with or without fee is hereby granted, provided that the above >> + * copyright notice and this permission notice appear in all copies. >> + * >> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES >> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF >> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR >> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES >> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN >> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF >> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. >> + */ >> +#ifndef CHACHA_POLY_AEAD_H >> +#define CHACHA_POLY_AEAD_H >> + >> +#include >> +#include "chacha.h" >> +#include "poly1305-donna-unrolled.h" >> + >> +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ >> + >> +struct chacha_poly_aead_ctx { >> + struct chacha_ctx main_ctx, header_ctx; >> +}; >> + >> +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, >> + const u_char *key, u_int keylen) >> + __attribute__((__bounded__(__buffer__, 2, 3))); >> +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, >> + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, >> + int do_encrypt); >> +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, >> + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) >> + __attribute__((__bounded__(__buffer__, 4, 5))); >> + >> +#endif /* CHACHA_POLY_AEAD_H */ >> Index: cipher.c >> =================================================================== >> RCS file: /var/cvs/openssh/cipher.c,v >> retrieving revision 1.97 >> diff -u -p -r1.97 cipher.c >> --- cipher.c 8 Nov 2013 01:16:50 -0000 1.97 >> +++ cipher.c 15 Nov 2013 00:08:29 -0000 >> @@ -43,9 +43,11 @@ >> >> #include >> #include >> +#include >> >> #include "xmalloc.h" >> #include "log.h" >> +#include "misc.h" >> #include "cipher.h" >> >> /* compatibility with old or broken OpenSSL versions */ >> @@ -63,7 +65,9 @@ struct Cipher { >> u_int iv_len; /* defaults to block_size */ >> u_int auth_len; >> u_int discard_len; >> - u_int cbc_mode; >> + u_int flags; >> +#define CFLAG_CBC (1<<0) >> +#define CFLAG_CP_AEAD (1<<1) >> const EVP_CIPHER *(*evptype)(void); >> }; >> >> @@ -95,6 +99,8 @@ static const struct Cipher ciphers[] = { >> { "aes256-gcm at openssh.com", >> SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, >> #endif >> + { "chacha20-poly1305 at openssh.com", >> + SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, >> { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } >> }; >> >> @@ -142,7 +148,12 @@ cipher_authlen(const Cipher *c) >> u_int >> cipher_ivlen(const Cipher *c) >> { >> - return (c->iv_len ? c->iv_len : c->block_size); >> + /* >> + * Default is cipher block size, except for chacha20+poly1305 that >> + * needs no IV. XXX make iv_len == -1 default? >> + */ >> + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? >> + c->iv_len : c->block_size; >> } >> >> u_int >> @@ -154,7 +165,7 @@ cipher_get_number(const Cipher *c) >> u_int >> cipher_is_cbc(const Cipher *c) >> { >> - return (c->cbc_mode); >> + return (c->flags & CFLAG_CBC) != 0; >> } >> >> u_int >> @@ -274,8 +285,11 @@ cipher_init(CipherContext *cc, const Cip >> ivlen, cipher->name); >> cc->cipher = cipher; >> >> + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { >> + cp_aead_init(&cc->cp_ctx, key, keylen); >> + return; >> + } >> type = (*cipher->evptype)(); >> - >> EVP_CIPHER_CTX_init(&cc->evp); >> #ifdef SSH_OLD_EVP >> if (type->key_len > 0 && type->key_len != keylen) { >> @@ -330,9 +344,15 @@ cipher_init(CipherContext *cc, const Cip >> * Both 'aadlen' and 'authlen' can be set to 0. >> */ >> void >> -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, >> +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, >> u_int len, u_int aadlen, u_int authlen) >> { >> + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { >> + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, >> + authlen, cc->encrypt) != 0) >> + fatal("Decryption integrity check failed"); >> + return; >> + } >> if (authlen) { >> u_char lastiv[1]; >> >> @@ -374,10 +394,29 @@ cipher_crypt(CipherContext *cc, u_char * >> } >> } >> >> +/* >> + * Extract the packet length for an AEAD cipher, including any decryption >> + * necessary beforehand. >> + */ >> +int >> +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, >> + const u_char *cp, u_int len) >> +{ >> + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) >> + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, >> + cp, len); >> + if (len < 4) >> + return -1; >> + *plenp = get_u32(cp); >> + return 0; >> +} >> + >> void >> cipher_cleanup(CipherContext *cc) >> { >> - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) >> + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) >> + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); >> + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) >> error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); >> } >> >> @@ -417,6 +456,8 @@ cipher_get_keyiv_len(const CipherContext >> >> if (c->number == SSH_CIPHER_3DES) >> ivlen = 24; >> + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) >> + ivlen = 0; >> else >> ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); >> return (ivlen); >> @@ -428,6 +469,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch >> const Cipher *c = cc->cipher; >> int evplen; >> >> + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { >> + if (len != 0) >> + fatal("%s: wrong iv length %d != %d", __func__, len, 0); >> + return; >> + } >> + >> switch (c->number) { >> case SSH_CIPHER_SSH2: >> case SSH_CIPHER_DES: >> @@ -463,6 +510,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch >> { >> const Cipher *c = cc->cipher; >> int evplen = 0; >> + >> + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) >> + return; >> >> switch (c->number) { >> case SSH_CIPHER_SSH2: >> Index: cipher.h >> =================================================================== >> RCS file: /var/cvs/openssh/cipher.h,v >> retrieving revision 1.37 >> diff -u -p -r1.37 cipher.h >> --- cipher.h 8 Nov 2013 01:16:50 -0000 1.37 >> +++ cipher.h 15 Nov 2013 00:08:29 -0000 >> @@ -38,6 +38,8 @@ >> #define CIPHER_H >> >> #include >> +#include "chacha20poly1305aead.h" >> + >> /* >> * Cipher types for SSH-1. New types can be added, but old types should not >> * be removed for compatibility. The maximum allowed value is 31. >> @@ -65,7 +67,9 @@ struct Cipher; >> struct CipherContext { >> int plaintext; >> int encrypt; >> + int is_cp_aead; >> EVP_CIPHER_CTX evp; >> + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ >> const Cipher *cipher; >> }; >> >> @@ -78,8 +82,10 @@ int ciphers_valid(const char *); >> char *cipher_alg_list(char); >> void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, >> const u_char *, u_int, int); >> -void cipher_crypt(CipherContext *, u_char *, const u_char *, >> +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, >> u_int, u_int, u_int); >> +int cipher_aead_get_length(CipherContext *, u_int *, u_int, >> + const u_char *, u_int); >> void cipher_cleanup(CipherContext *); >> void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); >> u_int cipher_blocksize(const Cipher *); >> Index: myproposal.h >> =================================================================== >> RCS file: /var/cvs/openssh/myproposal.h,v >> retrieving revision 1.43 >> diff -u -p -r1.43 myproposal.h >> --- myproposal.h 9 Nov 2013 07:39:25 -0000 1.43 >> +++ myproposal.h 15 Nov 2013 00:08:30 -0000 >> @@ -104,6 +104,7 @@ >> "aes128-ctr,aes192-ctr,aes256-ctr," \ >> "arcfour256,arcfour128," \ >> AESGCM_CIPHER_MODES \ >> + "chacha20-poly1305 at openssh.com," \ >> "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ >> "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" >> >> Index: packet.c >> =================================================================== >> RCS file: /var/cvs/openssh/packet.c,v >> retrieving revision 1.196 >> diff -u -p -r1.196 packet.c >> --- packet.c 8 Nov 2013 01:19:57 -0000 1.196 >> +++ packet.c 15 Nov 2013 00:08:30 -0000 >> @@ -713,7 +713,7 @@ packet_send1(void) >> buffer_append(&active_state->output, buf, 4); >> cp = buffer_append_space(&active_state->output, >> buffer_len(&active_state->outgoing_packet)); >> - cipher_crypt(&active_state->send_context, cp, >> + cipher_crypt(&active_state->send_context, 0, cp, >> buffer_ptr(&active_state->outgoing_packet), >> buffer_len(&active_state->outgoing_packet), 0, 0); >> >> @@ -946,8 +946,8 @@ packet_send2_wrapped(void) >> } >> /* encrypt packet and append to output buffer. */ >> cp = buffer_append_space(&active_state->output, len + authlen); >> - cipher_crypt(&active_state->send_context, cp, >> - buffer_ptr(&active_state->outgoing_packet), >> + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, >> + cp, buffer_ptr(&active_state->outgoing_packet), >> len - aadlen, aadlen, authlen); >> /* append unencrypted MAC */ >> if (mac && mac->enabled) { >> @@ -1208,7 +1208,7 @@ packet_read_poll1(void) >> /* Decrypt data to incoming_packet. */ >> buffer_clear(&active_state->incoming_packet); >> cp = buffer_append_space(&active_state->incoming_packet, padded_len); >> - cipher_crypt(&active_state->receive_context, cp, >> + cipher_crypt(&active_state->receive_context, 0, cp, >> buffer_ptr(&active_state->input), padded_len, 0, 0); >> >> buffer_consume(&active_state->input, padded_len); >> @@ -1279,10 +1279,12 @@ packet_read_poll2(u_int32_t *seqnr_p) >> aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; >> >> if (aadlen && active_state->packlen == 0) { >> - if (buffer_len(&active_state->input) < 4) >> + if (cipher_aead_get_length(&active_state->receive_context, >> + &active_state->packlen, >> + active_state->p_read.seqnr, >> + buffer_ptr(&active_state->input), >> + buffer_len(&active_state->input)) != 0) >> return SSH_MSG_NONE; >> - cp = buffer_ptr(&active_state->input); >> - active_state->packlen = get_u32(cp); >> if (active_state->packlen < 1 + 4 || >> active_state->packlen > PACKET_MAX_SIZE) { >> #ifdef PACKET_DEBUG >> @@ -1302,7 +1304,8 @@ packet_read_poll2(u_int32_t *seqnr_p) >> buffer_clear(&active_state->incoming_packet); >> cp = buffer_append_space(&active_state->incoming_packet, >> block_size); >> - cipher_crypt(&active_state->receive_context, cp, >> + cipher_crypt(&active_state->receive_context, >> + active_state->p_read.seqnr, cp, >> buffer_ptr(&active_state->input), block_size, 0, 0); >> cp = buffer_ptr(&active_state->incoming_packet); >> active_state->packlen = get_u32(cp); >> @@ -1357,7 +1360,8 @@ packet_read_poll2(u_int32_t *seqnr_p) >> macbuf = mac_compute(mac, active_state->p_read.seqnr, >> buffer_ptr(&active_state->input), aadlen + need); >> cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); >> - cipher_crypt(&active_state->receive_context, cp, >> + cipher_crypt(&active_state->receive_context, >> + active_state->p_read.seqnr, cp, >> buffer_ptr(&active_state->input), need, aadlen, authlen); >> buffer_consume(&active_state->input, aadlen + need + authlen); >> /* >> Index: poly1305-donna-unrolled.c >> =================================================================== >> RCS file: poly1305-donna-unrolled.c >> diff -N poly1305-donna-unrolled.c >> --- /dev/null 1 Jan 1970 00:00:00 -0000 >> +++ poly1305-donna-unrolled.c 15 Nov 2013 00:08:30 -0000 >> @@ -0,0 +1,154 @@ >> +/* >> + * Public Domain poly1305-donna from Andrew M. >> + * https://github.com/floodyberry/poly1305-donna >> + */ >> + >> +#include >> +#include >> + >> +#include "poly1305-donna-unrolled.h" >> + >> +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) >> + >> +#define U8TO32_LE(p) \ >> + (((uint32_t)((p)[0])) | \ >> + ((uint32_t)((p)[1]) << 8) | \ >> + ((uint32_t)((p)[2]) << 16) | \ >> + ((uint32_t)((p)[3]) << 24)) >> + >> +#define U32TO8_LE(p, v) \ >> + do { \ >> + (p)[0] = (uint8_t)((v)); \ >> + (p)[1] = (uint8_t)((v) >> 8); \ >> + (p)[2] = (uint8_t)((v) >> 16); \ >> + (p)[3] = (uint8_t)((v) >> 24); \ >> + } while (0) >> + >> +void >> +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { >> + uint32_t t0,t1,t2,t3; >> + uint32_t h0,h1,h2,h3,h4; >> + uint32_t r0,r1,r2,r3,r4; >> + uint32_t s1,s2,s3,s4; >> + uint32_t b, nb; >> + size_t j; >> + uint64_t t[5]; >> + uint64_t f0,f1,f2,f3; >> + uint32_t g0,g1,g2,g3,g4; >> + uint64_t c; >> + unsigned char mp[16]; >> + >> + /* clamp key */ >> + t0 = U8TO32_LE(key+0); >> + t1 = U8TO32_LE(key+4); >> + t2 = U8TO32_LE(key+8); >> + t3 = U8TO32_LE(key+12); >> + >> + /* precompute multipliers */ >> + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; >> + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; >> + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; >> + r3 = t2 & 0x3f03fff; t3 >>= 8; >> + r4 = t3 & 0x00fffff; >> + >> + s1 = r1 * 5; >> + s2 = r2 * 5; >> + s3 = r3 * 5; >> + s4 = r4 * 5; >> + >> + /* init state */ >> + h0 = 0; >> + h1 = 0; >> + h2 = 0; >> + h3 = 0; >> + h4 = 0; >> + >> + /* full blocks */ >> + if (inlen < 16) goto poly1305_donna_atmost15bytes; >> +poly1305_donna_16bytes: >> + m += 16; >> + inlen -= 16; >> + >> + t0 = U8TO32_LE(m-16); >> + t1 = U8TO32_LE(m-12); >> + t2 = U8TO32_LE(m-8); >> + t3 = U8TO32_LE(m-4); >> + >> + h0 += t0 & 0x3ffffff; >> + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; >> + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; >> + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; >> + h4 += (t3 >> 8) | (1 << 24); >> + >> + >> +poly1305_donna_mul: >> + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); >> + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); >> + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); >> + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); >> + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); >> + >> + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); >> + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); >> + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); >> + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); >> + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); >> + h0 += b * 5; >> + >> + if (inlen >= 16) goto poly1305_donna_16bytes; >> + >> + /* final bytes */ >> +poly1305_donna_atmost15bytes: >> + if (!inlen) goto poly1305_donna_finish; >> + >> + for (j = 0; j < inlen; j++) mp[j] = m[j]; >> + mp[j++] = 1; >> + for (; j < 16; j++) mp[j] = 0; >> + inlen = 0; >> + >> + t0 = U8TO32_LE(mp+0); >> + t1 = U8TO32_LE(mp+4); >> + t2 = U8TO32_LE(mp+8); >> + t3 = U8TO32_LE(mp+12); >> + >> + h0 += t0 & 0x3ffffff; >> + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; >> + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; >> + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; >> + h4 += (t3 >> 8); >> + >> + goto poly1305_donna_mul; >> + >> +poly1305_donna_finish: >> + b = h0 >> 26; h0 = h0 & 0x3ffffff; >> + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; >> + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; >> + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; >> + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; >> + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; >> + h1 += b; >> + >> + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; >> + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; >> + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; >> + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; >> + g4 = h4 + b - (1 << 26); >> + >> + b = (g4 >> 31) - 1; >> + nb = ~b; >> + h0 = (h0 & nb) | (g0 & b); >> + h1 = (h1 & nb) | (g1 & b); >> + h2 = (h2 & nb) | (g2 & b); >> + h3 = (h3 & nb) | (g3 & b); >> + h4 = (h4 & nb) | (g4 & b); >> + >> + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); >> + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); >> + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); >> + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); >> + >> + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); >> + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); >> + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); >> + U32TO8_LE(&out[12], f3); >> +} >> Index: poly1305-donna-unrolled.h >> =================================================================== >> RCS file: poly1305-donna-unrolled.h >> diff -N poly1305-donna-unrolled.h >> --- /dev/null 1 Jan 1970 00:00:00 -0000 >> +++ poly1305-donna-unrolled.h 15 Nov 2013 00:08:30 -0000 >> @@ -0,0 +1,22 @@ >> +/* $OpenBSD$ */ >> + >> +/* >> + * Public Domain poly1305-donna from Andrew M. >> + * https://github.com/floodyberry/poly1305-donna >> + */ >> + >> +#ifndef POLY1305_H >> +#define POLY1305_H >> + >> +#include >> + >> +#define POLY1305_KEYLEN 32 >> +#define POLY1305_TAGLEN 16 >> + >> +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, >> + const u_char key[POLY1305_KEYLEN]) >> + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) >> + __attribute__((__bounded__(__buffer__, 2, 3))) >> + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); >> + >> +#endif /* POLY1305_H */ >> _______________________________________________ >> openssh-unix-dev mailing list >> openssh-unix-dev at mindrot.org >> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev > > > > -- > This message is strictly personal and the opinions expressed do not > represent those of my employers, either past or present. -- This message is strictly personal and the opinions expressed do not represent those of my employers, either past or present. From loganaden at gmail.com Sat Nov 16 03:36:24 2013 From: loganaden at gmail.com (Loganaden Velvindron) Date: Fri, 15 Nov 2013 20:36:24 +0400 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: Also, add the list of cipher to the ssh_config.5 man page: --- ssh_config.5.orig 2013-11-15 20:33:03.746428778 +0400 +++ ssh_config.5 2013-11-15 20:35:11.075060099 +0400 @@ -348,8 +348,9 @@ The supported ciphers are .Dq arcfour256 , .Dq arcfour , .Dq blowfish-cbc , +.Dq cast128-cbc , and -.Dq cast128-cbc . +.Dq chacha20-poly1305 at openssh.com, The default is: .Bd -literal -offset 3n aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, On Fri, Nov 15, 2013 at 2:03 PM, Damien Miller wrote: > On Thu, 14 Nov 2013, James Cloos wrote: > >> >>>>> "DM" == Damien Miller writes: >> >> DM> Here's a diff to implement ChaCha20+Poly1305 as an authenticated >> DM> encryption mode. It authenticates the packet length and payload, >> DM> and uses a separate ChaCh20 instance to encrypt the packet length >> DM> to preserve privacy of packet lengths* while avoiding any decryption >> DM> oracle for the main packet payload. >> >> Cool. >> >> I'd like to test it out, but for logistics reasons I'll have to do so on >> a linux box. Is anything written on what is needed to convert from the >> openbsd cvs tree to the portable tree? Or do you have a version of the >> patch applicable to the portable's cvs? > > Here's one that applies to portable OpenSSH. Also available at > http://www.mindrot.org/files/chachapoly1305_04_portable.diff > > Index: Makefile.in > =================================================================== > RCS file: /var/cvs/openssh/Makefile.in,v > retrieving revision 1.344 > diff -u -p -r1.344 Makefile.in > --- Makefile.in 8 Nov 2013 13:17:41 -0000 1.344 > +++ Makefile.in 15 Nov 2013 00:08:29 -0000 > @@ -74,7 +74,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o > kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ > msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ > jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \ > - kexc25519.o kexc25519c.o > + kexc25519.o kexc25519c.o chacha.o chacha20poly1305aead.o \ > + poly1305-donna-unrolled.o > > SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ > sshconnect.o sshconnect1.o sshconnect2.o mux.o \ > Index: PROTOCOL > =================================================================== > RCS file: /var/cvs/openssh/PROTOCOL,v > retrieving revision 1.20 > diff -u -p -r1.20 PROTOCOL > --- PROTOCOL 17 Oct 2013 00:48:53 -0000 1.20 > +++ PROTOCOL 15 Nov 2013 00:08:29 -0000 > @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G > the exchanged MAC algorithms are ignored and there doesn't have to be > a matching MAC. > > +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption > + > +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 > +as described in PROTOCOL.chacha20poly1305. > + > 2. Connection protocol changes > > 2.1. connection: Channel write close extension "eow at openssh.com" > Index: PROTOCOL.chacha20poly1305 > =================================================================== > RCS file: PROTOCOL.chacha20poly1305 > diff -N PROTOCOL.chacha20poly1305 > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ PROTOCOL.chacha20poly1305 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,99 @@ > +This document describes the chacha20-poly1305 at openssh.com authenticated > +encryption cipher supported by OpenSSH. > + > +Background > +---------- > + > +ChaCha20 is a stream cipher designed by Daniel Bernstein and described > +in [1]. 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 stream output. > + > +Poly1305[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC > +that computes a 128 bit integrity tag given a message and a 256 bit key. > + > +The chacha20-poly1305 at openssh.com combines these two primitives into an > +autenticated encryption mode. The construction used is based on that > +proposed for TLS by Adam Langley in [3], but differs in the layout of > +data passed to the MAC and in the addition of encyption of the packet > +lengths. > + > +Negotiation > +----------- > + > +The chacha20-poly1305 at openssh.com offers both encryption and > +authentication. As such, no separate MAC is required. If the > +chacha20-poly1305 at openssh.com cipher is selected in key exchange, > +the offered MAC algorithms are ignored and no MAC is required to be > +negotiated. > + > +Detailed Construction > +--------------------- > + > +The chacha20-poly1305 at openssh.com cipher required 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 K_1 is a pure stream cipher that is used only > +to encrypt the 4 byte packet length field. The second instance, > +keyed by K_2, is used in conjunction with poly1305 to build an AEAD > +(Authenticated Encryption with Associated Data) that is used to encrypt > +and authenticate entire packet. > + > +Two separate cipher instances are used here so as to keep the packet > +lengths confidential but not create an oracle for the packet payload > +encryption by decrypting and using the packet length prior to checking > +the MAC. By using an independently-keyed cipher instance to encrypt the > +length, an active attacker seeking to exploit the packet input handling > +as a decryption oracle can learn nothing about the payload contents or > +its MAC (assuming key derivation is secure). > + > +The AEAD is constructed as follows: for each packet, generate a Poly1305 > +key by taking the first 256 bits of ChaCha20 stream output generated > +using K_2, an IV consisting of the packet sequence number encoded as an > +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of > +zero. The K_2 ChaCha20 block counter is then set to the little-endian > +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used > +for encryption of the packet payload. > + > +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 K_1 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 with the one appended to the packet and the packet > +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the > +encrypted length. Finally, calculate a MAC tag and append it. > + > +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 rekeying every 1GB of data > +sent or received. If this recommendation is followed, then > +chacha20-poly1305 at openssh.com requires no special handling in this area. > + > +References > +---------- > + > +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein > + http://cr.yp.to/chacha/chacha-20080128.pdf > + > +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein > + http://cr.yp.to/mac/poly1305-20050329.pdf > + > +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley > + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 > + > +$OpenBSD$ > + > Index: authfile.c > =================================================================== > RCS file: /var/cvs/openssh/authfile.c,v > retrieving revision 1.101 > diff -u -p -r1.101 authfile.c > --- authfile.c 1 Jun 2013 21:31:18 -0000 1.101 > +++ authfile.c 15 Nov 2013 00:08:29 -0000 > @@ -149,7 +149,7 @@ key_private_rsa1_to_blob(Key *key, Buffe > > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_ENCRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > @@ -473,7 +473,7 @@ key_parse_private_rsa1(Buffer *blob, con > /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_DECRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(©), buffer_len(©), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > Index: chacha.c > =================================================================== > RCS file: chacha.c > diff -N chacha.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.c 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,217 @@ > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > +#include > +#include "chacha.h" > + > +/* $OpenBSD$ */ > + > +typedef unsigned char u8; > +typedef unsigned int u32; > + > +typedef struct chacha_ctx chacha_ctx; > + > +#define U8C(v) (v##U) > +#define U32C(v) (v##U) > + > +#define U8V(v) ((u8)(v) & U8C(0xFF)) > +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) > + > +#define ROTL32(v, n) \ > + (U32V((v) << (n)) | ((v) >> (32 - (n)))) > + > +#define U8TO32_LITTLE(p) \ > + (((u32)((p)[0]) ) | \ > + ((u32)((p)[1]) << 8) | \ > + ((u32)((p)[2]) << 16) | \ > + ((u32)((p)[3]) << 24)) > + > +#define U32TO8_LITTLE(p, v) \ > + do { \ > + (p)[0] = U8V((v) ); \ > + (p)[1] = U8V((v) >> 8); \ > + (p)[2] = U8V((v) >> 16); \ > + (p)[3] = U8V((v) >> 24); \ > + } while (0) > + > +#define ROTATE(v,c) (ROTL32(v,c)) > +#define XOR(v,w) ((v) ^ (w)) > +#define PLUS(v,w) (U32V((v) + (w))) > +#define PLUSONE(v) (PLUS((v),1)) > + > +#define QUARTERROUND(a,b,c,d) \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); > + > +static const char sigma[16] = "expand 32-byte k"; > +static const char tau[16] = "expand 16-byte k"; > + > +void > +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) > +{ > + const char *constants; > + > + x->input[4] = U8TO32_LITTLE(k + 0); > + x->input[5] = U8TO32_LITTLE(k + 4); > + x->input[6] = U8TO32_LITTLE(k + 8); > + x->input[7] = U8TO32_LITTLE(k + 12); > + if (kbits == 256) { /* recommended */ > + k += 16; > + constants = sigma; > + } else { /* kbits == 128 */ > + constants = tau; > + } > + x->input[8] = U8TO32_LITTLE(k + 0); > + x->input[9] = U8TO32_LITTLE(k + 4); > + x->input[10] = U8TO32_LITTLE(k + 8); > + x->input[11] = U8TO32_LITTLE(k + 12); > + x->input[0] = U8TO32_LITTLE(constants + 0); > + x->input[1] = U8TO32_LITTLE(constants + 4); > + x->input[2] = U8TO32_LITTLE(constants + 8); > + x->input[3] = U8TO32_LITTLE(constants + 12); > +} > + > +void > +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) > +{ > + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); > + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); > + x->input[14] = U8TO32_LITTLE(iv + 0); > + x->input[15] = U8TO32_LITTLE(iv + 4); > +} > + > +void > +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) > +{ > + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; > + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; > + u8 *ctarget = NULL; > + u8 tmp[64]; > + u_int i; > + > + if (!bytes) return; > + > + j0 = x->input[0]; > + j1 = x->input[1]; > + j2 = x->input[2]; > + j3 = x->input[3]; > + j4 = x->input[4]; > + j5 = x->input[5]; > + j6 = x->input[6]; > + j7 = x->input[7]; > + j8 = x->input[8]; > + j9 = x->input[9]; > + j10 = x->input[10]; > + j11 = x->input[11]; > + j12 = x->input[12]; > + j13 = x->input[13]; > + j14 = x->input[14]; > + j15 = x->input[15]; > + > + for (;;) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) tmp[i] = m[i]; > + m = tmp; > + ctarget = c; > + c = tmp; > + } > + x0 = j0; > + x1 = j1; > + x2 = j2; > + x3 = j3; > + x4 = j4; > + x5 = j5; > + x6 = j6; > + x7 = j7; > + x8 = j8; > + x9 = j9; > + x10 = j10; > + x11 = j11; > + x12 = j12; > + x13 = j13; > + x14 = j14; > + x15 = j15; > + for (i = 20;i > 0;i -= 2) { > + QUARTERROUND( x0, x4, x8,x12) > + QUARTERROUND( x1, x5, x9,x13) > + QUARTERROUND( x2, x6,x10,x14) > + QUARTERROUND( x3, x7,x11,x15) > + QUARTERROUND( x0, x5,x10,x15) > + QUARTERROUND( x1, x6,x11,x12) > + QUARTERROUND( x2, x7, x8,x13) > + QUARTERROUND( x3, x4, x9,x14) > + } > + x0 = PLUS(x0,j0); > + x1 = PLUS(x1,j1); > + x2 = PLUS(x2,j2); > + x3 = PLUS(x3,j3); > + x4 = PLUS(x4,j4); > + x5 = PLUS(x5,j5); > + x6 = PLUS(x6,j6); > + x7 = PLUS(x7,j7); > + x8 = PLUS(x8,j8); > + x9 = PLUS(x9,j9); > + x10 = PLUS(x10,j10); > + x11 = PLUS(x11,j11); > + x12 = PLUS(x12,j12); > + x13 = PLUS(x13,j13); > + x14 = PLUS(x14,j14); > + x15 = PLUS(x15,j15); > + > + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); > + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); > + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); > + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); > + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); > + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); > + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); > + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); > + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); > + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); > + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); > + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); > + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); > + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); > + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); > + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); > + > + j12 = PLUSONE(j12); > + if (!j12) { > + j13 = PLUSONE(j13); > + /* stopping at 2^70 bytes per nonce is user's responsibility */ > + } > + > + U32TO8_LITTLE(c + 0,x0); > + U32TO8_LITTLE(c + 4,x1); > + U32TO8_LITTLE(c + 8,x2); > + U32TO8_LITTLE(c + 12,x3); > + U32TO8_LITTLE(c + 16,x4); > + U32TO8_LITTLE(c + 20,x5); > + U32TO8_LITTLE(c + 24,x6); > + U32TO8_LITTLE(c + 28,x7); > + U32TO8_LITTLE(c + 32,x8); > + U32TO8_LITTLE(c + 36,x9); > + U32TO8_LITTLE(c + 40,x10); > + U32TO8_LITTLE(c + 44,x11); > + U32TO8_LITTLE(c + 48,x12); > + U32TO8_LITTLE(c + 52,x13); > + U32TO8_LITTLE(c + 56,x14); > + U32TO8_LITTLE(c + 60,x15); > + > + if (bytes <= 64) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; > + } > + x->input[12] = j12; > + x->input[13] = j13; > + return; > + } > + bytes -= 64; > + c += 64; > + m += 64; > + } > +} > Index: chacha.h > =================================================================== > RCS file: chacha.h > diff -N chacha.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.h 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,35 @@ > +/* $OpenBSD$ */ > + > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > + > +#ifndef CHACHA_H > +#define CHACHA_H > + > +#include > + > +struct chacha_ctx { > + u_int input[16]; > +}; > + > +#define CHACHA_MINKEYLEN 16 > +#define CHACHA_NONCELEN 8 > +#define CHACHA_CTRLEN 8 > +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) > +#define CHACHA_BLOCKLEN 64 > + > +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); > +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) > + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); > +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, > + u_char *c, u_int bytes) > + __attribute__((__bounded__(__buffer__, 2, 4))) > + __attribute__((__bounded__(__buffer__, 3, 4))); > + > +#endif /* CHACHA_H */ > + > Index: chacha20poly1305aead.c > =================================================================== > RCS file: chacha20poly1305aead.c > diff -N chacha20poly1305aead.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.c 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,111 @@ > +/* > + * Copyright (c) 2013 Damien Miller > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include > +#include /* needed for misc.h */ > +#include /* needed for log.h */ > +#include > +#include /* needed for misc.h */ > + > +#include "log.h" > +#include "misc.h" > +#include "chacha20poly1305aead.h" > + > +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, > + const u_char *key, u_int keylen) > +{ > + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ > + fatal("%s: invalid keylen %u", __func__, keylen); > + chacha_keysetup(&ctx->main_ctx, key, 256); > + chacha_keysetup(&ctx->header_ctx, key + 32, 256); > +} > + > +/* > + * cp_aead_crypt() operates as following: > + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. > + * Theses bytes are treated as additional authenticated data. > + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. > + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the > + * authentication tag. > + * This tag is written on encryption and verified on decryption. > + * Both 'aadlen' and 'authlen' can be set to 0. > + */ > +int > +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, > + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) > +{ > + u_char seqbuf[8]; > + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ > + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; > + int r = -1; > + > + /* > + * Run ChaCha20 once to generate the Poly1305 key. The IV is the > + * packet sequence number. > + */ > + bzero(poly_key, sizeof(poly_key)); > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->main_ctx, > + poly_key, poly_key, sizeof(poly_key)); > + /* Set Chacha's block counter to 1 */ > + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); > + > + /* If decrypting, check tag before anything else */ > + if (!do_encrypt) { > + const u_char *tag = src + aadlen + len; > + > + poly1305_auth(expected_tag, src, aadlen + len, poly_key); > + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) > + goto out; > + } > + /* Crypt additional data */ > + if (aadlen) { > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); > + } > + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, > + dest + aadlen, len); > + > + /* If encrypting, calculate and append tag */ > + if (do_encrypt) { > + poly1305_auth(dest + aadlen + len, dest, aadlen + len, > + poly_key); > + } > + r = 0; > + > + out: > + bzero(expected_tag, sizeof(expected_tag)); > + bzero(seqbuf, sizeof(seqbuf)); > + bzero(poly_key, sizeof(poly_key)); > + return r; > +} > + > +int > +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > +{ > + u_char buf[4], seqbuf[8]; > + > + if (len < 4) > + return -1; /* Insufficient length */ > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); > + *plenp = get_u32(buf); > + return 0; > +} > + > Index: chacha20poly1305aead.h > =================================================================== > RCS file: chacha20poly1305aead.h > diff -N chacha20poly1305aead.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.h 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,41 @@ > +/* $OpenBSD$ */ > + > +/* > + * Copyright (c) Damien Miller 2013 > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > +#ifndef CHACHA_POLY_AEAD_H > +#define CHACHA_POLY_AEAD_H > + > +#include > +#include "chacha.h" > +#include "poly1305-donna-unrolled.h" > + > +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ > + > +struct chacha_poly_aead_ctx { > + struct chacha_ctx main_ctx, header_ctx; > +}; > + > +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, > + const u_char *key, u_int keylen) > + __attribute__((__bounded__(__buffer__, 2, 3))); > +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, > + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, > + int do_encrypt); > +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > + __attribute__((__bounded__(__buffer__, 4, 5))); > + > +#endif /* CHACHA_POLY_AEAD_H */ > Index: cipher.c > =================================================================== > RCS file: /var/cvs/openssh/cipher.c,v > retrieving revision 1.97 > diff -u -p -r1.97 cipher.c > --- cipher.c 8 Nov 2013 01:16:50 -0000 1.97 > +++ cipher.c 15 Nov 2013 00:08:29 -0000 > @@ -43,9 +43,11 @@ > > #include > #include > +#include > > #include "xmalloc.h" > #include "log.h" > +#include "misc.h" > #include "cipher.h" > > /* compatibility with old or broken OpenSSL versions */ > @@ -63,7 +65,9 @@ struct Cipher { > u_int iv_len; /* defaults to block_size */ > u_int auth_len; > u_int discard_len; > - u_int cbc_mode; > + u_int flags; > +#define CFLAG_CBC (1<<0) > +#define CFLAG_CP_AEAD (1<<1) > const EVP_CIPHER *(*evptype)(void); > }; > > @@ -95,6 +99,8 @@ static const struct Cipher ciphers[] = { > { "aes256-gcm at openssh.com", > SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, > #endif > + { "chacha20-poly1305 at openssh.com", > + SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, > { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } > }; > > @@ -142,7 +148,12 @@ cipher_authlen(const Cipher *c) > u_int > cipher_ivlen(const Cipher *c) > { > - return (c->iv_len ? c->iv_len : c->block_size); > + /* > + * Default is cipher block size, except for chacha20+poly1305 that > + * needs no IV. XXX make iv_len == -1 default? > + */ > + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? > + c->iv_len : c->block_size; > } > > u_int > @@ -154,7 +165,7 @@ cipher_get_number(const Cipher *c) > u_int > cipher_is_cbc(const Cipher *c) > { > - return (c->cbc_mode); > + return (c->flags & CFLAG_CBC) != 0; > } > > u_int > @@ -274,8 +285,11 @@ cipher_init(CipherContext *cc, const Cip > ivlen, cipher->name); > cc->cipher = cipher; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + cp_aead_init(&cc->cp_ctx, key, keylen); > + return; > + } > type = (*cipher->evptype)(); > - > EVP_CIPHER_CTX_init(&cc->evp); > #ifdef SSH_OLD_EVP > if (type->key_len > 0 && type->key_len != keylen) { > @@ -330,9 +344,15 @@ cipher_init(CipherContext *cc, const Cip > * Both 'aadlen' and 'authlen' can be set to 0. > */ > void > -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, > +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, > u_int len, u_int aadlen, u_int authlen) > { > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, > + authlen, cc->encrypt) != 0) > + fatal("Decryption integrity check failed"); > + return; > + } > if (authlen) { > u_char lastiv[1]; > > @@ -374,10 +394,29 @@ cipher_crypt(CipherContext *cc, u_char * > } > } > > +/* > + * Extract the packet length for an AEAD cipher, including any decryption > + * necessary beforehand. > + */ > +int > +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, > + const u_char *cp, u_int len) > +{ > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, > + cp, len); > + if (len < 4) > + return -1; > + *plenp = get_u32(cp); > + return 0; > +} > + > void > cipher_cleanup(CipherContext *cc) > { > - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); > + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); > } > > @@ -417,6 +456,8 @@ cipher_get_keyiv_len(const CipherContext > > if (c->number == SSH_CIPHER_3DES) > ivlen = 24; > + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + ivlen = 0; > else > ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); > return (ivlen); > @@ -428,6 +469,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch > const Cipher *c = cc->cipher; > int evplen; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (len != 0) > + fatal("%s: wrong iv length %d != %d", __func__, len, 0); > + return; > + } > + > switch (c->number) { > case SSH_CIPHER_SSH2: > case SSH_CIPHER_DES: > @@ -463,6 +510,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch > { > const Cipher *c = cc->cipher; > int evplen = 0; > + > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return; > > switch (c->number) { > case SSH_CIPHER_SSH2: > Index: cipher.h > =================================================================== > RCS file: /var/cvs/openssh/cipher.h,v > retrieving revision 1.37 > diff -u -p -r1.37 cipher.h > --- cipher.h 8 Nov 2013 01:16:50 -0000 1.37 > +++ cipher.h 15 Nov 2013 00:08:29 -0000 > @@ -38,6 +38,8 @@ > #define CIPHER_H > > #include > +#include "chacha20poly1305aead.h" > + > /* > * Cipher types for SSH-1. New types can be added, but old types should not > * be removed for compatibility. The maximum allowed value is 31. > @@ -65,7 +67,9 @@ struct Cipher; > struct CipherContext { > int plaintext; > int encrypt; > + int is_cp_aead; > EVP_CIPHER_CTX evp; > + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ > const Cipher *cipher; > }; > > @@ -78,8 +82,10 @@ int ciphers_valid(const char *); > char *cipher_alg_list(char); > void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, > const u_char *, u_int, int); > -void cipher_crypt(CipherContext *, u_char *, const u_char *, > +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, > u_int, u_int, u_int); > +int cipher_aead_get_length(CipherContext *, u_int *, u_int, > + const u_char *, u_int); > void cipher_cleanup(CipherContext *); > void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); > u_int cipher_blocksize(const Cipher *); > Index: myproposal.h > =================================================================== > RCS file: /var/cvs/openssh/myproposal.h,v > retrieving revision 1.43 > diff -u -p -r1.43 myproposal.h > --- myproposal.h 9 Nov 2013 07:39:25 -0000 1.43 > +++ myproposal.h 15 Nov 2013 00:08:30 -0000 > @@ -104,6 +104,7 @@ > "aes128-ctr,aes192-ctr,aes256-ctr," \ > "arcfour256,arcfour128," \ > AESGCM_CIPHER_MODES \ > + "chacha20-poly1305 at openssh.com," \ > "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ > "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" > > Index: packet.c > =================================================================== > RCS file: /var/cvs/openssh/packet.c,v > retrieving revision 1.196 > diff -u -p -r1.196 packet.c > --- packet.c 8 Nov 2013 01:19:57 -0000 1.196 > +++ packet.c 15 Nov 2013 00:08:30 -0000 > @@ -713,7 +713,7 @@ packet_send1(void) > buffer_append(&active_state->output, buf, 4); > cp = buffer_append_space(&active_state->output, > buffer_len(&active_state->outgoing_packet)); > - cipher_crypt(&active_state->send_context, cp, > + cipher_crypt(&active_state->send_context, 0, cp, > buffer_ptr(&active_state->outgoing_packet), > buffer_len(&active_state->outgoing_packet), 0, 0); > > @@ -946,8 +946,8 @@ packet_send2_wrapped(void) > } > /* encrypt packet and append to output buffer. */ > cp = buffer_append_space(&active_state->output, len + authlen); > - cipher_crypt(&active_state->send_context, cp, > - buffer_ptr(&active_state->outgoing_packet), > + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, > + cp, buffer_ptr(&active_state->outgoing_packet), > len - aadlen, aadlen, authlen); > /* append unencrypted MAC */ > if (mac && mac->enabled) { > @@ -1208,7 +1208,7 @@ packet_read_poll1(void) > /* Decrypt data to incoming_packet. */ > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, padded_len); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, 0, cp, > buffer_ptr(&active_state->input), padded_len, 0, 0); > > buffer_consume(&active_state->input, padded_len); > @@ -1279,10 +1279,12 @@ packet_read_poll2(u_int32_t *seqnr_p) > aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; > > if (aadlen && active_state->packlen == 0) { > - if (buffer_len(&active_state->input) < 4) > + if (cipher_aead_get_length(&active_state->receive_context, > + &active_state->packlen, > + active_state->p_read.seqnr, > + buffer_ptr(&active_state->input), > + buffer_len(&active_state->input)) != 0) > return SSH_MSG_NONE; > - cp = buffer_ptr(&active_state->input); > - active_state->packlen = get_u32(cp); > if (active_state->packlen < 1 + 4 || > active_state->packlen > PACKET_MAX_SIZE) { > #ifdef PACKET_DEBUG > @@ -1302,7 +1304,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, > block_size); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), block_size, 0, 0); > cp = buffer_ptr(&active_state->incoming_packet); > active_state->packlen = get_u32(cp); > @@ -1357,7 +1360,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > macbuf = mac_compute(mac, active_state->p_read.seqnr, > buffer_ptr(&active_state->input), aadlen + need); > cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), need, aadlen, authlen); > buffer_consume(&active_state->input, aadlen + need + authlen); > /* > Index: poly1305-donna-unrolled.c > =================================================================== > RCS file: poly1305-donna-unrolled.c > diff -N poly1305-donna-unrolled.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.c 15 Nov 2013 00:08:30 -0000 > @@ -0,0 +1,154 @@ > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#include > +#include > + > +#include "poly1305-donna-unrolled.h" > + > +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) > + > +#define U8TO32_LE(p) \ > + (((uint32_t)((p)[0])) | \ > + ((uint32_t)((p)[1]) << 8) | \ > + ((uint32_t)((p)[2]) << 16) | \ > + ((uint32_t)((p)[3]) << 24)) > + > +#define U32TO8_LE(p, v) \ > + do { \ > + (p)[0] = (uint8_t)((v)); \ > + (p)[1] = (uint8_t)((v) >> 8); \ > + (p)[2] = (uint8_t)((v) >> 16); \ > + (p)[3] = (uint8_t)((v) >> 24); \ > + } while (0) > + > +void > +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { > + uint32_t t0,t1,t2,t3; > + uint32_t h0,h1,h2,h3,h4; > + uint32_t r0,r1,r2,r3,r4; > + uint32_t s1,s2,s3,s4; > + uint32_t b, nb; > + size_t j; > + uint64_t t[5]; > + uint64_t f0,f1,f2,f3; > + uint32_t g0,g1,g2,g3,g4; > + uint64_t c; > + unsigned char mp[16]; > + > + /* clamp key */ > + t0 = U8TO32_LE(key+0); > + t1 = U8TO32_LE(key+4); > + t2 = U8TO32_LE(key+8); > + t3 = U8TO32_LE(key+12); > + > + /* precompute multipliers */ > + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; > + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; > + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; > + r3 = t2 & 0x3f03fff; t3 >>= 8; > + r4 = t3 & 0x00fffff; > + > + s1 = r1 * 5; > + s2 = r2 * 5; > + s3 = r3 * 5; > + s4 = r4 * 5; > + > + /* init state */ > + h0 = 0; > + h1 = 0; > + h2 = 0; > + h3 = 0; > + h4 = 0; > + > + /* full blocks */ > + if (inlen < 16) goto poly1305_donna_atmost15bytes; > +poly1305_donna_16bytes: > + m += 16; > + inlen -= 16; > + > + t0 = U8TO32_LE(m-16); > + t1 = U8TO32_LE(m-12); > + t2 = U8TO32_LE(m-8); > + t3 = U8TO32_LE(m-4); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8) | (1 << 24); > + > + > +poly1305_donna_mul: > + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); > + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); > + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); > + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); > + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); > + > + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); > + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); > + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); > + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); > + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); > + h0 += b * 5; > + > + if (inlen >= 16) goto poly1305_donna_16bytes; > + > + /* final bytes */ > +poly1305_donna_atmost15bytes: > + if (!inlen) goto poly1305_donna_finish; > + > + for (j = 0; j < inlen; j++) mp[j] = m[j]; > + mp[j++] = 1; > + for (; j < 16; j++) mp[j] = 0; > + inlen = 0; > + > + t0 = U8TO32_LE(mp+0); > + t1 = U8TO32_LE(mp+4); > + t2 = U8TO32_LE(mp+8); > + t3 = U8TO32_LE(mp+12); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8); > + > + goto poly1305_donna_mul; > + > +poly1305_donna_finish: > + b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; > + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; > + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; > + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; > + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; > + > + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; > + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; > + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; > + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; > + g4 = h4 + b - (1 << 26); > + > + b = (g4 >> 31) - 1; > + nb = ~b; > + h0 = (h0 & nb) | (g0 & b); > + h1 = (h1 & nb) | (g1 & b); > + h2 = (h2 & nb) | (g2 & b); > + h3 = (h3 & nb) | (g3 & b); > + h4 = (h4 & nb) | (g4 & b); > + > + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); > + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); > + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); > + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); > + > + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); > + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); > + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); > + U32TO8_LE(&out[12], f3); > +} > Index: poly1305-donna-unrolled.h > =================================================================== > RCS file: poly1305-donna-unrolled.h > diff -N poly1305-donna-unrolled.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.h 15 Nov 2013 00:08:30 -0000 > @@ -0,0 +1,22 @@ > +/* $OpenBSD$ */ > + > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#ifndef POLY1305_H > +#define POLY1305_H > + > +#include > + > +#define POLY1305_KEYLEN 32 > +#define POLY1305_TAGLEN 16 > + > +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, > + const u_char key[POLY1305_KEYLEN]) > + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) > + __attribute__((__bounded__(__buffer__, 2, 3))) > + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); > + > +#endif /* POLY1305_H */ > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- This message is strictly personal and the opinions expressed do not represent those of my employers, either past or present. From loganaden at gmail.com Sat Nov 16 03:46:41 2013 From: loganaden at gmail.com (Loganaden Velvindron) Date: Fri, 15 Nov 2013 20:46:41 +0400 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Fri, Nov 15, 2013 at 2:03 PM, Damien Miller wrote: > On Thu, 14 Nov 2013, James Cloos wrote: > >> >>>>> "DM" == Damien Miller writes: >> >> DM> Here's a diff to implement ChaCha20+Poly1305 as an authenticated >> DM> encryption mode. It authenticates the packet length and payload, >> DM> and uses a separate ChaCh20 instance to encrypt the packet length >> DM> to preserve privacy of packet lengths* while avoiding any decryption >> DM> oracle for the main packet payload. >> >> Cool. >> >> I'd like to test it out, but for logistics reasons I'll have to do so on >> a linux box. Is anything written on what is needed to convert from the >> openbsd cvs tree to the portable tree? Or do you have a version of the >> patch applicable to the portable's cvs? > > Here's one that applies to portable OpenSSH. Also available at > http://www.mindrot.org/files/chachapoly1305_04_portable.diff No issues so far :-) Yeah, I made sure to specify the new cipher using -c. > > Index: Makefile.in > =================================================================== > RCS file: /var/cvs/openssh/Makefile.in,v > retrieving revision 1.344 > diff -u -p -r1.344 Makefile.in > --- Makefile.in 8 Nov 2013 13:17:41 -0000 1.344 > +++ Makefile.in 15 Nov 2013 00:08:29 -0000 > @@ -74,7 +74,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o > kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ > msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ > jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \ > - kexc25519.o kexc25519c.o > + kexc25519.o kexc25519c.o chacha.o chacha20poly1305aead.o \ > + poly1305-donna-unrolled.o > > SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ > sshconnect.o sshconnect1.o sshconnect2.o mux.o \ > Index: PROTOCOL > =================================================================== > RCS file: /var/cvs/openssh/PROTOCOL,v > retrieving revision 1.20 > diff -u -p -r1.20 PROTOCOL > --- PROTOCOL 17 Oct 2013 00:48:53 -0000 1.20 > +++ PROTOCOL 15 Nov 2013 00:08:29 -0000 > @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G > the exchanged MAC algorithms are ignored and there doesn't have to be > a matching MAC. > > +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption > + > +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 > +as described in PROTOCOL.chacha20poly1305. > + > 2. Connection protocol changes > > 2.1. connection: Channel write close extension "eow at openssh.com" > Index: PROTOCOL.chacha20poly1305 > =================================================================== > RCS file: PROTOCOL.chacha20poly1305 > diff -N PROTOCOL.chacha20poly1305 > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ PROTOCOL.chacha20poly1305 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,99 @@ > +This document describes the chacha20-poly1305 at openssh.com authenticated > +encryption cipher supported by OpenSSH. > + > +Background > +---------- > + > +ChaCha20 is a stream cipher designed by Daniel Bernstein and described > +in [1]. 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 stream output. > + > +Poly1305[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC > +that computes a 128 bit integrity tag given a message and a 256 bit key. > + > +The chacha20-poly1305 at openssh.com combines these two primitives into an > +autenticated encryption mode. The construction used is based on that > +proposed for TLS by Adam Langley in [3], but differs in the layout of > +data passed to the MAC and in the addition of encyption of the packet > +lengths. > + > +Negotiation > +----------- > + > +The chacha20-poly1305 at openssh.com offers both encryption and > +authentication. As such, no separate MAC is required. If the > +chacha20-poly1305 at openssh.com cipher is selected in key exchange, > +the offered MAC algorithms are ignored and no MAC is required to be > +negotiated. > + > +Detailed Construction > +--------------------- > + > +The chacha20-poly1305 at openssh.com cipher required 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 K_1 is a pure stream cipher that is used only > +to encrypt the 4 byte packet length field. The second instance, > +keyed by K_2, is used in conjunction with poly1305 to build an AEAD > +(Authenticated Encryption with Associated Data) that is used to encrypt > +and authenticate entire packet. > + > +Two separate cipher instances are used here so as to keep the packet > +lengths confidential but not create an oracle for the packet payload > +encryption by decrypting and using the packet length prior to checking > +the MAC. By using an independently-keyed cipher instance to encrypt the > +length, an active attacker seeking to exploit the packet input handling > +as a decryption oracle can learn nothing about the payload contents or > +its MAC (assuming key derivation is secure). > + > +The AEAD is constructed as follows: for each packet, generate a Poly1305 > +key by taking the first 256 bits of ChaCha20 stream output generated > +using K_2, an IV consisting of the packet sequence number encoded as an > +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of > +zero. The K_2 ChaCha20 block counter is then set to the little-endian > +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used > +for encryption of the packet payload. > + > +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 K_1 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 with the one appended to the packet and the packet > +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the > +encrypted length. Finally, calculate a MAC tag and append it. > + > +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 rekeying every 1GB of data > +sent or received. If this recommendation is followed, then > +chacha20-poly1305 at openssh.com requires no special handling in this area. > + > +References > +---------- > + > +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein > + http://cr.yp.to/chacha/chacha-20080128.pdf > + > +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein > + http://cr.yp.to/mac/poly1305-20050329.pdf > + > +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley > + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 > + > +$OpenBSD$ > + > Index: authfile.c > =================================================================== > RCS file: /var/cvs/openssh/authfile.c,v > retrieving revision 1.101 > diff -u -p -r1.101 authfile.c > --- authfile.c 1 Jun 2013 21:31:18 -0000 1.101 > +++ authfile.c 15 Nov 2013 00:08:29 -0000 > @@ -149,7 +149,7 @@ key_private_rsa1_to_blob(Key *key, Buffe > > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_ENCRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > @@ -473,7 +473,7 @@ key_parse_private_rsa1(Buffer *blob, con > /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ > cipher_set_key_string(&ciphercontext, cipher, passphrase, > CIPHER_DECRYPT); > - cipher_crypt(&ciphercontext, cp, > + cipher_crypt(&ciphercontext, 0, cp, > buffer_ptr(©), buffer_len(©), 0, 0); > cipher_cleanup(&ciphercontext); > memset(&ciphercontext, 0, sizeof(ciphercontext)); > Index: chacha.c > =================================================================== > RCS file: chacha.c > diff -N chacha.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.c 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,217 @@ > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > +#include > +#include "chacha.h" > + > +/* $OpenBSD$ */ > + > +typedef unsigned char u8; > +typedef unsigned int u32; > + > +typedef struct chacha_ctx chacha_ctx; > + > +#define U8C(v) (v##U) > +#define U32C(v) (v##U) > + > +#define U8V(v) ((u8)(v) & U8C(0xFF)) > +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) > + > +#define ROTL32(v, n) \ > + (U32V((v) << (n)) | ((v) >> (32 - (n)))) > + > +#define U8TO32_LITTLE(p) \ > + (((u32)((p)[0]) ) | \ > + ((u32)((p)[1]) << 8) | \ > + ((u32)((p)[2]) << 16) | \ > + ((u32)((p)[3]) << 24)) > + > +#define U32TO8_LITTLE(p, v) \ > + do { \ > + (p)[0] = U8V((v) ); \ > + (p)[1] = U8V((v) >> 8); \ > + (p)[2] = U8V((v) >> 16); \ > + (p)[3] = U8V((v) >> 24); \ > + } while (0) > + > +#define ROTATE(v,c) (ROTL32(v,c)) > +#define XOR(v,w) ((v) ^ (w)) > +#define PLUS(v,w) (U32V((v) + (w))) > +#define PLUSONE(v) (PLUS((v),1)) > + > +#define QUARTERROUND(a,b,c,d) \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ > + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ > + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); > + > +static const char sigma[16] = "expand 32-byte k"; > +static const char tau[16] = "expand 16-byte k"; > + > +void > +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) > +{ > + const char *constants; > + > + x->input[4] = U8TO32_LITTLE(k + 0); > + x->input[5] = U8TO32_LITTLE(k + 4); > + x->input[6] = U8TO32_LITTLE(k + 8); > + x->input[7] = U8TO32_LITTLE(k + 12); > + if (kbits == 256) { /* recommended */ > + k += 16; > + constants = sigma; > + } else { /* kbits == 128 */ > + constants = tau; > + } > + x->input[8] = U8TO32_LITTLE(k + 0); > + x->input[9] = U8TO32_LITTLE(k + 4); > + x->input[10] = U8TO32_LITTLE(k + 8); > + x->input[11] = U8TO32_LITTLE(k + 12); > + x->input[0] = U8TO32_LITTLE(constants + 0); > + x->input[1] = U8TO32_LITTLE(constants + 4); > + x->input[2] = U8TO32_LITTLE(constants + 8); > + x->input[3] = U8TO32_LITTLE(constants + 12); > +} > + > +void > +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) > +{ > + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); > + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); > + x->input[14] = U8TO32_LITTLE(iv + 0); > + x->input[15] = U8TO32_LITTLE(iv + 4); > +} > + > +void > +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) > +{ > + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; > + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; > + u8 *ctarget = NULL; > + u8 tmp[64]; > + u_int i; > + > + if (!bytes) return; > + > + j0 = x->input[0]; > + j1 = x->input[1]; > + j2 = x->input[2]; > + j3 = x->input[3]; > + j4 = x->input[4]; > + j5 = x->input[5]; > + j6 = x->input[6]; > + j7 = x->input[7]; > + j8 = x->input[8]; > + j9 = x->input[9]; > + j10 = x->input[10]; > + j11 = x->input[11]; > + j12 = x->input[12]; > + j13 = x->input[13]; > + j14 = x->input[14]; > + j15 = x->input[15]; > + > + for (;;) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) tmp[i] = m[i]; > + m = tmp; > + ctarget = c; > + c = tmp; > + } > + x0 = j0; > + x1 = j1; > + x2 = j2; > + x3 = j3; > + x4 = j4; > + x5 = j5; > + x6 = j6; > + x7 = j7; > + x8 = j8; > + x9 = j9; > + x10 = j10; > + x11 = j11; > + x12 = j12; > + x13 = j13; > + x14 = j14; > + x15 = j15; > + for (i = 20;i > 0;i -= 2) { > + QUARTERROUND( x0, x4, x8,x12) > + QUARTERROUND( x1, x5, x9,x13) > + QUARTERROUND( x2, x6,x10,x14) > + QUARTERROUND( x3, x7,x11,x15) > + QUARTERROUND( x0, x5,x10,x15) > + QUARTERROUND( x1, x6,x11,x12) > + QUARTERROUND( x2, x7, x8,x13) > + QUARTERROUND( x3, x4, x9,x14) > + } > + x0 = PLUS(x0,j0); > + x1 = PLUS(x1,j1); > + x2 = PLUS(x2,j2); > + x3 = PLUS(x3,j3); > + x4 = PLUS(x4,j4); > + x5 = PLUS(x5,j5); > + x6 = PLUS(x6,j6); > + x7 = PLUS(x7,j7); > + x8 = PLUS(x8,j8); > + x9 = PLUS(x9,j9); > + x10 = PLUS(x10,j10); > + x11 = PLUS(x11,j11); > + x12 = PLUS(x12,j12); > + x13 = PLUS(x13,j13); > + x14 = PLUS(x14,j14); > + x15 = PLUS(x15,j15); > + > + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); > + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); > + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); > + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); > + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); > + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); > + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); > + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); > + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); > + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); > + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); > + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); > + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); > + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); > + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); > + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); > + > + j12 = PLUSONE(j12); > + if (!j12) { > + j13 = PLUSONE(j13); > + /* stopping at 2^70 bytes per nonce is user's responsibility */ > + } > + > + U32TO8_LITTLE(c + 0,x0); > + U32TO8_LITTLE(c + 4,x1); > + U32TO8_LITTLE(c + 8,x2); > + U32TO8_LITTLE(c + 12,x3); > + U32TO8_LITTLE(c + 16,x4); > + U32TO8_LITTLE(c + 20,x5); > + U32TO8_LITTLE(c + 24,x6); > + U32TO8_LITTLE(c + 28,x7); > + U32TO8_LITTLE(c + 32,x8); > + U32TO8_LITTLE(c + 36,x9); > + U32TO8_LITTLE(c + 40,x10); > + U32TO8_LITTLE(c + 44,x11); > + U32TO8_LITTLE(c + 48,x12); > + U32TO8_LITTLE(c + 52,x13); > + U32TO8_LITTLE(c + 56,x14); > + U32TO8_LITTLE(c + 60,x15); > + > + if (bytes <= 64) { > + if (bytes < 64) { > + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; > + } > + x->input[12] = j12; > + x->input[13] = j13; > + return; > + } > + bytes -= 64; > + c += 64; > + m += 64; > + } > +} > Index: chacha.h > =================================================================== > RCS file: chacha.h > diff -N chacha.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha.h 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,35 @@ > +/* $OpenBSD$ */ > + > +/* > +chacha-merged.c version 20080118 > +D. J. Bernstein > +Public domain. > +*/ > + > +#ifndef CHACHA_H > +#define CHACHA_H > + > +#include > + > +struct chacha_ctx { > + u_int input[16]; > +}; > + > +#define CHACHA_MINKEYLEN 16 > +#define CHACHA_NONCELEN 8 > +#define CHACHA_CTRLEN 8 > +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) > +#define CHACHA_BLOCKLEN 64 > + > +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); > +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) > + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) > + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); > +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, > + u_char *c, u_int bytes) > + __attribute__((__bounded__(__buffer__, 2, 4))) > + __attribute__((__bounded__(__buffer__, 3, 4))); > + > +#endif /* CHACHA_H */ > + > Index: chacha20poly1305aead.c > =================================================================== > RCS file: chacha20poly1305aead.c > diff -N chacha20poly1305aead.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.c 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,111 @@ > +/* > + * Copyright (c) 2013 Damien Miller > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include > +#include /* needed for misc.h */ > +#include /* needed for log.h */ > +#include > +#include /* needed for misc.h */ > + > +#include "log.h" > +#include "misc.h" > +#include "chacha20poly1305aead.h" > + > +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, > + const u_char *key, u_int keylen) > +{ > + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ > + fatal("%s: invalid keylen %u", __func__, keylen); > + chacha_keysetup(&ctx->main_ctx, key, 256); > + chacha_keysetup(&ctx->header_ctx, key + 32, 256); > +} > + > +/* > + * cp_aead_crypt() operates as following: > + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. > + * Theses bytes are treated as additional authenticated data. > + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. > + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the > + * authentication tag. > + * This tag is written on encryption and verified on decryption. > + * Both 'aadlen' and 'authlen' can be set to 0. > + */ > +int > +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, > + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) > +{ > + u_char seqbuf[8]; > + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ > + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; > + int r = -1; > + > + /* > + * Run ChaCha20 once to generate the Poly1305 key. The IV is the > + * packet sequence number. > + */ > + bzero(poly_key, sizeof(poly_key)); > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->main_ctx, > + poly_key, poly_key, sizeof(poly_key)); > + /* Set Chacha's block counter to 1 */ > + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); > + > + /* If decrypting, check tag before anything else */ > + if (!do_encrypt) { > + const u_char *tag = src + aadlen + len; > + > + poly1305_auth(expected_tag, src, aadlen + len, poly_key); > + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) > + goto out; > + } > + /* Crypt additional data */ > + if (aadlen) { > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); > + } > + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, > + dest + aadlen, len); > + > + /* If encrypting, calculate and append tag */ > + if (do_encrypt) { > + poly1305_auth(dest + aadlen + len, dest, aadlen + len, > + poly_key); > + } > + r = 0; > + > + out: > + bzero(expected_tag, sizeof(expected_tag)); > + bzero(seqbuf, sizeof(seqbuf)); > + bzero(poly_key, sizeof(poly_key)); > + return r; > +} > + > +int > +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > +{ > + u_char buf[4], seqbuf[8]; > + > + if (len < 4) > + return -1; /* Insufficient length */ > + put_u64(seqbuf, seqnr); > + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); > + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); > + *plenp = get_u32(buf); > + return 0; > +} > + > Index: chacha20poly1305aead.h > =================================================================== > RCS file: chacha20poly1305aead.h > diff -N chacha20poly1305aead.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ chacha20poly1305aead.h 15 Nov 2013 00:08:29 -0000 > @@ -0,0 +1,41 @@ > +/* $OpenBSD$ */ > + > +/* > + * Copyright (c) Damien Miller 2013 > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > +#ifndef CHACHA_POLY_AEAD_H > +#define CHACHA_POLY_AEAD_H > + > +#include > +#include "chacha.h" > +#include "poly1305-donna-unrolled.h" > + > +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ > + > +struct chacha_poly_aead_ctx { > + struct chacha_ctx main_ctx, header_ctx; > +}; > + > +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, > + const u_char *key, u_int keylen) > + __attribute__((__bounded__(__buffer__, 2, 3))); > +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, > + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, > + int do_encrypt); > +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, > + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) > + __attribute__((__bounded__(__buffer__, 4, 5))); > + > +#endif /* CHACHA_POLY_AEAD_H */ > Index: cipher.c > =================================================================== > RCS file: /var/cvs/openssh/cipher.c,v > retrieving revision 1.97 > diff -u -p -r1.97 cipher.c > --- cipher.c 8 Nov 2013 01:16:50 -0000 1.97 > +++ cipher.c 15 Nov 2013 00:08:29 -0000 > @@ -43,9 +43,11 @@ > > #include > #include > +#include > > #include "xmalloc.h" > #include "log.h" > +#include "misc.h" > #include "cipher.h" > > /* compatibility with old or broken OpenSSL versions */ > @@ -63,7 +65,9 @@ struct Cipher { > u_int iv_len; /* defaults to block_size */ > u_int auth_len; > u_int discard_len; > - u_int cbc_mode; > + u_int flags; > +#define CFLAG_CBC (1<<0) > +#define CFLAG_CP_AEAD (1<<1) > const EVP_CIPHER *(*evptype)(void); > }; > > @@ -95,6 +99,8 @@ static const struct Cipher ciphers[] = { > { "aes256-gcm at openssh.com", > SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, > #endif > + { "chacha20-poly1305 at openssh.com", > + SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, > { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } > }; > > @@ -142,7 +148,12 @@ cipher_authlen(const Cipher *c) > u_int > cipher_ivlen(const Cipher *c) > { > - return (c->iv_len ? c->iv_len : c->block_size); > + /* > + * Default is cipher block size, except for chacha20+poly1305 that > + * needs no IV. XXX make iv_len == -1 default? > + */ > + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? > + c->iv_len : c->block_size; > } > > u_int > @@ -154,7 +165,7 @@ cipher_get_number(const Cipher *c) > u_int > cipher_is_cbc(const Cipher *c) > { > - return (c->cbc_mode); > + return (c->flags & CFLAG_CBC) != 0; > } > > u_int > @@ -274,8 +285,11 @@ cipher_init(CipherContext *cc, const Cip > ivlen, cipher->name); > cc->cipher = cipher; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + cp_aead_init(&cc->cp_ctx, key, keylen); > + return; > + } > type = (*cipher->evptype)(); > - > EVP_CIPHER_CTX_init(&cc->evp); > #ifdef SSH_OLD_EVP > if (type->key_len > 0 && type->key_len != keylen) { > @@ -330,9 +344,15 @@ cipher_init(CipherContext *cc, const Cip > * Both 'aadlen' and 'authlen' can be set to 0. > */ > void > -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, > +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, > u_int len, u_int aadlen, u_int authlen) > { > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, > + authlen, cc->encrypt) != 0) > + fatal("Decryption integrity check failed"); > + return; > + } > if (authlen) { > u_char lastiv[1]; > > @@ -374,10 +394,29 @@ cipher_crypt(CipherContext *cc, u_char * > } > } > > +/* > + * Extract the packet length for an AEAD cipher, including any decryption > + * necessary beforehand. > + */ > +int > +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, > + const u_char *cp, u_int len) > +{ > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, > + cp, len); > + if (len < 4) > + return -1; > + *plenp = get_u32(cp); > + return 0; > +} > + > void > cipher_cleanup(CipherContext *cc) > { > - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); > + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) > error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); > } > > @@ -417,6 +456,8 @@ cipher_get_keyiv_len(const CipherContext > > if (c->number == SSH_CIPHER_3DES) > ivlen = 24; > + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + ivlen = 0; > else > ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); > return (ivlen); > @@ -428,6 +469,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch > const Cipher *c = cc->cipher; > int evplen; > > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { > + if (len != 0) > + fatal("%s: wrong iv length %d != %d", __func__, len, 0); > + return; > + } > + > switch (c->number) { > case SSH_CIPHER_SSH2: > case SSH_CIPHER_DES: > @@ -463,6 +510,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch > { > const Cipher *c = cc->cipher; > int evplen = 0; > + > + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) > + return; > > switch (c->number) { > case SSH_CIPHER_SSH2: > Index: cipher.h > =================================================================== > RCS file: /var/cvs/openssh/cipher.h,v > retrieving revision 1.37 > diff -u -p -r1.37 cipher.h > --- cipher.h 8 Nov 2013 01:16:50 -0000 1.37 > +++ cipher.h 15 Nov 2013 00:08:29 -0000 > @@ -38,6 +38,8 @@ > #define CIPHER_H > > #include > +#include "chacha20poly1305aead.h" > + > /* > * Cipher types for SSH-1. New types can be added, but old types should not > * be removed for compatibility. The maximum allowed value is 31. > @@ -65,7 +67,9 @@ struct Cipher; > struct CipherContext { > int plaintext; > int encrypt; > + int is_cp_aead; > EVP_CIPHER_CTX evp; > + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ > const Cipher *cipher; > }; > > @@ -78,8 +82,10 @@ int ciphers_valid(const char *); > char *cipher_alg_list(char); > void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, > const u_char *, u_int, int); > -void cipher_crypt(CipherContext *, u_char *, const u_char *, > +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, > u_int, u_int, u_int); > +int cipher_aead_get_length(CipherContext *, u_int *, u_int, > + const u_char *, u_int); > void cipher_cleanup(CipherContext *); > void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); > u_int cipher_blocksize(const Cipher *); > Index: myproposal.h > =================================================================== > RCS file: /var/cvs/openssh/myproposal.h,v > retrieving revision 1.43 > diff -u -p -r1.43 myproposal.h > --- myproposal.h 9 Nov 2013 07:39:25 -0000 1.43 > +++ myproposal.h 15 Nov 2013 00:08:30 -0000 > @@ -104,6 +104,7 @@ > "aes128-ctr,aes192-ctr,aes256-ctr," \ > "arcfour256,arcfour128," \ > AESGCM_CIPHER_MODES \ > + "chacha20-poly1305 at openssh.com," \ > "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ > "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" > > Index: packet.c > =================================================================== > RCS file: /var/cvs/openssh/packet.c,v > retrieving revision 1.196 > diff -u -p -r1.196 packet.c > --- packet.c 8 Nov 2013 01:19:57 -0000 1.196 > +++ packet.c 15 Nov 2013 00:08:30 -0000 > @@ -713,7 +713,7 @@ packet_send1(void) > buffer_append(&active_state->output, buf, 4); > cp = buffer_append_space(&active_state->output, > buffer_len(&active_state->outgoing_packet)); > - cipher_crypt(&active_state->send_context, cp, > + cipher_crypt(&active_state->send_context, 0, cp, > buffer_ptr(&active_state->outgoing_packet), > buffer_len(&active_state->outgoing_packet), 0, 0); > > @@ -946,8 +946,8 @@ packet_send2_wrapped(void) > } > /* encrypt packet and append to output buffer. */ > cp = buffer_append_space(&active_state->output, len + authlen); > - cipher_crypt(&active_state->send_context, cp, > - buffer_ptr(&active_state->outgoing_packet), > + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, > + cp, buffer_ptr(&active_state->outgoing_packet), > len - aadlen, aadlen, authlen); > /* append unencrypted MAC */ > if (mac && mac->enabled) { > @@ -1208,7 +1208,7 @@ packet_read_poll1(void) > /* Decrypt data to incoming_packet. */ > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, padded_len); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, 0, cp, > buffer_ptr(&active_state->input), padded_len, 0, 0); > > buffer_consume(&active_state->input, padded_len); > @@ -1279,10 +1279,12 @@ packet_read_poll2(u_int32_t *seqnr_p) > aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; > > if (aadlen && active_state->packlen == 0) { > - if (buffer_len(&active_state->input) < 4) > + if (cipher_aead_get_length(&active_state->receive_context, > + &active_state->packlen, > + active_state->p_read.seqnr, > + buffer_ptr(&active_state->input), > + buffer_len(&active_state->input)) != 0) > return SSH_MSG_NONE; > - cp = buffer_ptr(&active_state->input); > - active_state->packlen = get_u32(cp); > if (active_state->packlen < 1 + 4 || > active_state->packlen > PACKET_MAX_SIZE) { > #ifdef PACKET_DEBUG > @@ -1302,7 +1304,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > buffer_clear(&active_state->incoming_packet); > cp = buffer_append_space(&active_state->incoming_packet, > block_size); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), block_size, 0, 0); > cp = buffer_ptr(&active_state->incoming_packet); > active_state->packlen = get_u32(cp); > @@ -1357,7 +1360,8 @@ packet_read_poll2(u_int32_t *seqnr_p) > macbuf = mac_compute(mac, active_state->p_read.seqnr, > buffer_ptr(&active_state->input), aadlen + need); > cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); > - cipher_crypt(&active_state->receive_context, cp, > + cipher_crypt(&active_state->receive_context, > + active_state->p_read.seqnr, cp, > buffer_ptr(&active_state->input), need, aadlen, authlen); > buffer_consume(&active_state->input, aadlen + need + authlen); > /* > Index: poly1305-donna-unrolled.c > =================================================================== > RCS file: poly1305-donna-unrolled.c > diff -N poly1305-donna-unrolled.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.c 15 Nov 2013 00:08:30 -0000 > @@ -0,0 +1,154 @@ > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#include > +#include > + > +#include "poly1305-donna-unrolled.h" > + > +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) > + > +#define U8TO32_LE(p) \ > + (((uint32_t)((p)[0])) | \ > + ((uint32_t)((p)[1]) << 8) | \ > + ((uint32_t)((p)[2]) << 16) | \ > + ((uint32_t)((p)[3]) << 24)) > + > +#define U32TO8_LE(p, v) \ > + do { \ > + (p)[0] = (uint8_t)((v)); \ > + (p)[1] = (uint8_t)((v) >> 8); \ > + (p)[2] = (uint8_t)((v) >> 16); \ > + (p)[3] = (uint8_t)((v) >> 24); \ > + } while (0) > + > +void > +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { > + uint32_t t0,t1,t2,t3; > + uint32_t h0,h1,h2,h3,h4; > + uint32_t r0,r1,r2,r3,r4; > + uint32_t s1,s2,s3,s4; > + uint32_t b, nb; > + size_t j; > + uint64_t t[5]; > + uint64_t f0,f1,f2,f3; > + uint32_t g0,g1,g2,g3,g4; > + uint64_t c; > + unsigned char mp[16]; > + > + /* clamp key */ > + t0 = U8TO32_LE(key+0); > + t1 = U8TO32_LE(key+4); > + t2 = U8TO32_LE(key+8); > + t3 = U8TO32_LE(key+12); > + > + /* precompute multipliers */ > + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; > + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; > + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; > + r3 = t2 & 0x3f03fff; t3 >>= 8; > + r4 = t3 & 0x00fffff; > + > + s1 = r1 * 5; > + s2 = r2 * 5; > + s3 = r3 * 5; > + s4 = r4 * 5; > + > + /* init state */ > + h0 = 0; > + h1 = 0; > + h2 = 0; > + h3 = 0; > + h4 = 0; > + > + /* full blocks */ > + if (inlen < 16) goto poly1305_donna_atmost15bytes; > +poly1305_donna_16bytes: > + m += 16; > + inlen -= 16; > + > + t0 = U8TO32_LE(m-16); > + t1 = U8TO32_LE(m-12); > + t2 = U8TO32_LE(m-8); > + t3 = U8TO32_LE(m-4); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8) | (1 << 24); > + > + > +poly1305_donna_mul: > + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); > + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); > + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); > + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); > + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); > + > + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); > + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); > + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); > + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); > + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); > + h0 += b * 5; > + > + if (inlen >= 16) goto poly1305_donna_16bytes; > + > + /* final bytes */ > +poly1305_donna_atmost15bytes: > + if (!inlen) goto poly1305_donna_finish; > + > + for (j = 0; j < inlen; j++) mp[j] = m[j]; > + mp[j++] = 1; > + for (; j < 16; j++) mp[j] = 0; > + inlen = 0; > + > + t0 = U8TO32_LE(mp+0); > + t1 = U8TO32_LE(mp+4); > + t2 = U8TO32_LE(mp+8); > + t3 = U8TO32_LE(mp+12); > + > + h0 += t0 & 0x3ffffff; > + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; > + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; > + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; > + h4 += (t3 >> 8); > + > + goto poly1305_donna_mul; > + > +poly1305_donna_finish: > + b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; > + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; > + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; > + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; > + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; > + h1 += b; > + > + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; > + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; > + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; > + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; > + g4 = h4 + b - (1 << 26); > + > + b = (g4 >> 31) - 1; > + nb = ~b; > + h0 = (h0 & nb) | (g0 & b); > + h1 = (h1 & nb) | (g1 & b); > + h2 = (h2 & nb) | (g2 & b); > + h3 = (h3 & nb) | (g3 & b); > + h4 = (h4 & nb) | (g4 & b); > + > + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); > + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); > + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); > + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); > + > + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); > + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); > + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); > + U32TO8_LE(&out[12], f3); > +} > Index: poly1305-donna-unrolled.h > =================================================================== > RCS file: poly1305-donna-unrolled.h > diff -N poly1305-donna-unrolled.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ poly1305-donna-unrolled.h 15 Nov 2013 00:08:30 -0000 > @@ -0,0 +1,22 @@ > +/* $OpenBSD$ */ > + > +/* > + * Public Domain poly1305-donna from Andrew M. > + * https://github.com/floodyberry/poly1305-donna > + */ > + > +#ifndef POLY1305_H > +#define POLY1305_H > + > +#include > + > +#define POLY1305_KEYLEN 32 > +#define POLY1305_TAGLEN 16 > + > +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, > + const u_char key[POLY1305_KEYLEN]) > + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) > + __attribute__((__bounded__(__buffer__, 2, 3))) > + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); > + > +#endif /* POLY1305_H */ > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- This message is strictly personal and the opinions expressed do not represent those of my employers, either past or present. From naddy at mips.inka.de Sun Nov 17 03:43:19 2013 From: naddy at mips.inka.de (Christian Weisgerber) Date: Sat, 16 Nov 2013 16:43:19 +0000 (UTC) Subject: Rekey regression test: How is GCM magical? Message-ID: Revision 1.10 of regress/usr.bin/ssh/rekey.sh has added this: # GCM is magical so test with all KexAlgorithms [...] How is GCM magical? Is chacha20-poly1305 equally magical and needs testing with all KexAlgorithms as well? (chacha20-poly1305 doesn't work with diffie-hellman-group1-sha1 because the latter can't provide the required 512 bits of key material.) -- Christian "naddy" Weisgerber naddy at mips.inka.de From mfriedl at gmail.com Sun Nov 17 06:19:49 2013 From: mfriedl at gmail.com (Markus Friedl) Date: Sat, 16 Nov 2013 20:19:49 +0100 Subject: Rekey regression test: How is GCM magical? In-Reply-To: References: Message-ID: <0C119CD9-D9CB-468B-9D5C-7B10D2198A12@gmail.com> Am 16.11.2013 um 17:43 schrieb Christian Weisgerber : > Revision 1.10 of regress/usr.bin/ssh/rekey.sh has added this: > > # GCM is magical so test with all KexAlgorithms > [...] > > How is GCM magical? just because there is no MAC. so it makes sense to trigger more than the default KEX. > Is chacha20-poly1305 equally magical and needs testing with all > KexAlgorithms as well? in this sense, yes. > > (chacha20-poly1305 doesn't work with diffie-hellman-group1-sha1 > because the latter can't provide the required 512 bits of key > material.) why should it not work? in this case the key gets expanded, even if the security margin of the kex is smaller. -m From naddy at mips.inka.de Sun Nov 17 06:59:52 2013 From: naddy at mips.inka.de (Christian Weisgerber) Date: Sat, 16 Nov 2013 20:59:52 +0100 Subject: Rekey regression test: How is GCM magical? In-Reply-To: <0C119CD9-D9CB-468B-9D5C-7B10D2198A12@gmail.com> References: <0C119CD9-D9CB-468B-9D5C-7B10D2198A12@gmail.com> Message-ID: <20131116195952.GA17218@lorvorc.mips.inka.de> Markus Friedl: > > (chacha20-poly1305 doesn't work with diffie-hellman-group1-sha1 > > because the latter can't provide the required 512 bits of key > > material.) > > why should it not work? in this case the key gets expanded, > even if the security margin of the kex is smaller. Well, it doesn't. $ ssh -c chacha20-poly1305 at openssh.com -oKexAlgorithms=diffie-hellman-group1-sha1 localhost dh_gen_key: group too small: 1024 (2*need 1024) -- Christian "naddy" Weisgerber naddy at mips.inka.de From naddy at mips.inka.de Sun Nov 17 07:11:15 2013 From: naddy at mips.inka.de (Christian Weisgerber) Date: Sat, 16 Nov 2013 20:11:15 +0000 (UTC) Subject: chacha20+poly1305 authenticated encryption References: Message-ID: Damien Miller wrote: > Here's a diff to implement ChaCha20+Poly1305 as an authenticated > encryption mode. Unless I'm hallucinating, this patch has a catastrophic bug. I updated and ran the regression tests, and the integrity check fails: test integrity: chacha20-poly1305 at openssh.com @2900 ssh -c chacha20-poly1305 at openssh.com succeeds with bit-flip at 2900 unexpected error mac chacha20-poly1305 at openssh.com at 2900 test integrity: chacha20-poly1305 at openssh.com @2901 ssh -c chacha20-poly1305 at openssh.com succeeds with bit-flip at 2901 unexpected error mac chacha20-poly1305 at openssh.com at 2901 [etc.] In cp_aead_crypt()... > + /* If decrypting, check tag before anything else */ > + if (!do_encrypt) { > + const u_char *tag = src + aadlen + len; > + > + poly1305_auth(expected_tag, src, aadlen + len, poly_key); > + if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) > + goto out; > + } ... the condition for the tag comparison is inverted. It only seems to work because the authentication actually fails all the time. There must be a bug somewhere else, but I don't see it. -- Christian "naddy" Weisgerber naddy at mips.inka.de From cloos at jhcloos.com Sun Nov 17 09:37:06 2013 From: cloos at jhcloos.com (James Cloos) Date: Sat, 16 Nov 2013 17:37:06 -0500 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: (Damien Miller's message of "Fri, 15 Nov 2013 21:03:11 +1100 (EST)") References: Message-ID: My first test is for speed on the kinds of systems where I regularly need bulk transfers over ssh. On kvm, where aesni is unavailable, chacha20-poly1305 at openssh.com is more than twice as fast as aes128-gcm at openssh.com and about 20% faster than aes128-cbc. But on a box where aesni *is* available, chacha20-poly1305 is 85% as fast as aes128-cbc and about 45% as fast as aes128-gcm. (On each test box chacha20-poly1305 had, as expected, about the same performance. Aes128-gcm, OTOH, was five times as fast with aesni as without and aes128-cbc was about 60% faster with aesni.) Provided aes128-gcm and chacha20-poly1305 both are implmented correctly, the latter will be a significant win fo many use cases. (AIUI, gcm has proven relatively easy to implement *in*-correctly, and poly1305 is supposed to avoid that, but performance also can be a valid consideration.) To make it easier for me, I put a snapshot of cvs head w/ the patches from this thread at: https://github.com/jhcloos/openssh-chacha-poly1305 Make tests is still running.... -JimC -- James Cloos OpenPGP: 1024D/ED7DAEA6 From naddy at mips.inka.de Sun Nov 17 10:56:44 2013 From: naddy at mips.inka.de (Christian Weisgerber) Date: Sat, 16 Nov 2013 23:56:44 +0000 (UTC) Subject: chacha20+poly1305 authenticated encryption References: Message-ID: Christian Weisgerber wrote: > I updated and ran the regression tests, PS: Here's the diff for the test suite. Index: cipher-speed.sh =================================================================== RCS file: /cvs/src/regress/usr.bin/ssh/cipher-speed.sh,v retrieving revision 1.10 diff -u -p -r1.10 cipher-speed.sh --- cipher-speed.sh 7 Nov 2013 02:48:38 -0000 1.10 +++ cipher-speed.sh 15 Nov 2013 13:52:29 -0000 @@ -25,7 +25,8 @@ for c in `${SSH} -Q cipher`; do n=0; for done # No point trying all MACs for GCM since they are ignored. case $c in - aes*-gcm at openssh.com) test $n -gt 0 && break;; + aes*-gcm at openssh.com|chacha20-poly1305 at openssh.com) + test $n -gt 0 && break;; esac n=$(($n + 1)) done; done Index: integrity.sh =================================================================== RCS file: /cvs/src/regress/usr.bin/ssh/integrity.sh,v retrieving revision 1.11 diff -u -p -r1.11 integrity.sh --- integrity.sh 7 Nov 2013 02:48:38 -0000 1.11 +++ integrity.sh 16 Nov 2013 00:27:24 -0000 @@ -11,7 +11,7 @@ startoffset=2900 macs=`${SSH} -Q mac` # The following are not MACs, but ciphers with integrated integrity. They are # handled specially below. -macs="$macs `${SSH} -Q cipher | grep gcm at openssh.com`" +macs="$macs `${SSH} -Q cipher | egrep '(gcm|poly1305)@openssh.com'`" # sshd-command for proxy (see test-exec.sh) cmd="sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSHD_LOGFILE} -i -f $OBJ/sshd_proxy" @@ -31,14 +31,14 @@ for m in $macs; do # modify output from sshd at offset $off pxy="proxycommand=$cmd | $OBJ/modpipe -wm xor:$off:1" case $m in - aes*gcm*) macopt="-c $m";; - *) macopt="-m $m";; + aes*gcm*|chacha*poly*) macopt="-c $m";; + *) macopt="-m $m";; esac verbose "test $tid: $m @$off" ${SSH} $macopt -2F $OBJ/ssh_proxy -o "$pxy" \ 999.999.999.999 'printf "%4096s" " "' >/dev/null if [ $? -eq 0 ]; then - fail "ssh -m $m succeeds with bit-flip at $off" + fail "ssh $macopt succeeds with bit-flip at $off" fi ecnt=$((ecnt+1)) output=$(tail -2 $TEST_SSH_LOGFILE | egrep -v "^debug" | \ Index: rekey.sh =================================================================== RCS file: /cvs/src/regress/usr.bin/ssh/rekey.sh,v retrieving revision 1.13 diff -u -p -r1.13 rekey.sh --- rekey.sh 9 Nov 2013 05:41:34 -0000 1.13 +++ rekey.sh 16 Nov 2013 23:53:18 -0000 @@ -45,8 +45,8 @@ for opt in $opts; do done # GCM is magical so test with all KexAlgorithms -if ${SSH} -Q cipher | grep gcm at openssh.com >/dev/null ; then - for c in `${SSH} -Q cipher | grep gcm at openssh.com`; do +if ${SSH} -Q cipher | egrep '(gcm|poly1305)@openssh.com' >/dev/null ; then + for c in `${SSH} -Q cipher | egrep '(gcm|poly1305)@openssh.com'`; do for kex in `${SSH} -Q kex`; do verbose "client rekey $c $kex" ssh_data_rekeying -oRekeyLimit=256k -oCiphers=$c -oKexAlgorithms=$kex Index: try-ciphers.sh =================================================================== RCS file: /cvs/src/regress/usr.bin/ssh/try-ciphers.sh,v retrieving revision 1.21 diff -u -p -r1.21 try-ciphers.sh --- try-ciphers.sh 7 Nov 2013 02:48:38 -0000 1.21 +++ try-ciphers.sh 15 Nov 2013 13:52:48 -0000 @@ -14,7 +14,8 @@ for c in `${SSH} -Q cipher`; do fi # No point trying all MACs for GCM since they are ignored. case $c in - aes*-gcm at openssh.com) test $n -gt 0 && break;; + aes*-gcm at openssh.com|chacha20-poly1305 at openssh.com) + test $n -gt 0 && break;; esac n=`expr $n + 1` done -- Christian "naddy" Weisgerber naddy at mips.inka.de From jessep3 at hushmail.com Sun Nov 17 11:48:44 2013 From: jessep3 at hushmail.com (Jesse P.) Date: Sat, 16 Nov 2013 19:48:44 -0500 Subject: Default ciphers list Message-ID: <20131117004844.B3FD920111@smtp.hushmail.com> Hi. I was reading the sshd_config manpage and wondering why the default ciphers are: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, aes128-gcm at openssh.com,aes256-gcm at openssh.com, aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, aes256-cbc,arcfour Wasn't AES-GCM supposed to be more secure and recommended? It's been bumped down a bit. Also, why is CTR preferred over CBC? Thanks. From naddy at mips.inka.de Sun Nov 17 12:27:19 2013 From: naddy at mips.inka.de (Christian Weisgerber) Date: Sun, 17 Nov 2013 01:27:19 +0000 (UTC) Subject: Default ciphers list References: <20131117004844.B3FD920111@smtp.hushmail.com> Message-ID: Jesse P. wrote: > Hi. I was reading the sshd_config manpage and wondering why the default > ciphers are: > > aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, > aes128-gcm at openssh.com,aes256-gcm at openssh.com, > aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, > aes256-cbc,arcfour > > Wasn't AES-GCM supposed to be more secure and recommended? AES-GCM performs relatively poorly without hardware support (such as AESNI). > Also, why is CTR preferred over CBC? Thanks. http://www.openssh.com/txt/cbc.adv -- Christian "naddy" Weisgerber naddy at mips.inka.de From naddy at mips.inka.de Sun Nov 17 13:49:48 2013 From: naddy at mips.inka.de (Christian Weisgerber) Date: Sun, 17 Nov 2013 02:49:48 +0000 (UTC) Subject: chacha20+poly1305 authenticated encryption References: Message-ID: Christian Weisgerber wrote: > There must be a bug somewhere else, but I don't see it. Found it. The authentication tag size was wrong in the ciphers table. With the changes below, this now passes the relevant regression tests on alpha, amd64, and sparc64; and I verified that these architectures all interoperate successfully. --- chacha20poly1305aead.c.orig Sun Nov 17 02:38:00 2013 +++ chacha20poly1305aead.c Sun Nov 17 02:38:16 2013 @@ -68,7 +68,7 @@ cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int const u_char *tag = src + aadlen + len; poly1305_auth(expected_tag, src, aadlen + len, poly_key); - if (!timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN)) + if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) goto out; } /* Crypt additional data */ --- cipher.c.orig Sun Nov 17 02:37:52 2013 +++ cipher.c Sun Nov 17 02:38:30 2013 @@ -93,7 +93,7 @@ static const struct Cipher ciphers[] = { { "aes256-gcm at openssh.com", SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, { "chacha20-poly1305 at openssh.com", - SSH_CIPHER_SSH2, 8, 64, 0, 8, 0, CFLAG_CP_AEAD, NULL }, + SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CP_AEAD, NULL }, { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } }; -- Christian "naddy" Weisgerber naddy at mips.inka.de From djm at mindrot.org Sun Nov 17 14:35:34 2013 From: djm at mindrot.org (Damien Miller) Date: Sun, 17 Nov 2013 14:35:34 +1100 (EST) Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Sat, 16 Nov 2013, James Cloos wrote: > My first test is for speed on the kinds of systems where I regularly > need bulk transfers over ssh. > > On kvm, where aesni is unavailable, chacha20-poly1305 at openssh.com is > more than twice as fast as aes128-gcm at openssh.com and about 20% faster > than aes128-cbc. > > But on a box where aesni *is* available, chacha20-poly1305 is 85% as > fast as aes128-cbc and about 45% as fast as aes128-gcm. There is plenty of room for improvement - both the Poly1305 and ChaCha20 implementations in the patch are plain C. There are significantly faster versions available in libnacl/libsodium. Once this code lands in OpenSSH, I'll probably add some way to use these external libraries in portable OpenSSH. -d From djm at mindrot.org Sun Nov 17 19:37:37 2013 From: djm at mindrot.org (Damien Miller) Date: Sun, 17 Nov 2013 19:37:37 +1100 (EST) Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Sun, 17 Nov 2013, Christian Weisgerber wrote: > Christian Weisgerber wrote: > > > There must be a bug somewhere else, but I don't see it. > > Found it. The authentication tag size was wrong in the ciphers > table. With the changes below, this now passes the relevant > regression tests on alpha, amd64, and sparc64; and I verified that > these architectures all interoperate successfully. Thanks, good catches. -d From djm at mindrot.org Mon Nov 18 01:01:40 2013 From: djm at mindrot.org (Damien Miller) Date: Mon, 18 Nov 2013 01:01:40 +1100 (EST) Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Sun, 17 Nov 2013, Damien Miller wrote: > On Sun, 17 Nov 2013, Christian Weisgerber wrote: > > > Christian Weisgerber wrote: > > > > > There must be a bug somewhere else, but I don't see it. > > > > Found it. The authentication tag size was wrong in the ciphers > > table. With the changes below, this now passes the relevant > > regression tests on alpha, amd64, and sparc64; and I verified that > > these architectures all interoperate successfully. > > Thanks, good catches. This incorporates naddy's fixes, adds a "cipher-auth" query mode (ssh -Q cipher-auth) that lists only ciphers that offer authenticated encryption and uses this to better automate the regress tests. Index: usr.bin/ssh/PROTOCOL =================================================================== RCS file: /cvs/src/usr.bin/ssh/PROTOCOL,v retrieving revision 1.21 diff -u -p -r1.21 PROTOCOL --- usr.bin/ssh/PROTOCOL 17 Oct 2013 00:30:13 -0000 1.21 +++ usr.bin/ssh/PROTOCOL 17 Nov 2013 13:57:29 -0000 @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-G the exchanged MAC algorithms are ignored and there doesn't have to be a matching MAC. +1.7 transport: chacha20-poly1305 at openssh.com authenticated encryption + +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 +as described in PROTOCOL.chacha20poly1305. + 2. Connection protocol changes 2.1. connection: Channel write close extension "eow at openssh.com" Index: usr.bin/ssh/PROTOCOL.chacha20poly1305 =================================================================== RCS file: usr.bin/ssh/PROTOCOL.chacha20poly1305 diff -N usr.bin/ssh/PROTOCOL.chacha20poly1305 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ssh/PROTOCOL.chacha20poly1305 17 Nov 2013 13:57:29 -0000 @@ -0,0 +1,102 @@ +This document describes the chacha20-poly1305 at openssh.com authenticated +encryption cipher supported by OpenSSH. + +Background +---------- + +ChaCha20 is a stream cipher designed by Daniel Bernstein and described +in [1]. 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[2] also by Daniel Bernstien is a one-time Carter-Wegman MAC +that computes a 128 bit integrity tag given a message and a 256 bit key. + +The chacha20-poly1305 at openssh.com combines these two primitives into an +authenticated encryption mode. The construction used is based on that +proposed for TLS by Adam Langley in [3], but differs in the layout of +data passed to the MAC and in the addition of encyption of the packet +lengths. + +Negotiation +----------- + +The chacha20-poly1305 at openssh.com offers both encryption and +authentication. As such, no separate MAC is required. If the +chacha20-poly1305 at openssh.com cipher is selected in key exchange, +the offered MAC algorithms are ignored and no MAC is required to be +negotiated. + +Detailed Construction +--------------------- + +The chacha20-poly1305 at openssh.com 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 K_1 is a stream cipher that is used only +to encrypt the 4 byte packet length field. The second instance, +keyed by K_2, is used in conjunction with poly1305 to build an AEAD +(Authenticated Encryption with Associated Data) that is used to encrypt +and authenticate the entire packet. + +Two separate cipher instances are used here so as to keep the packet +lengths confidential but not create an oracle for the packet payload +encryption by decrypting and using the packet length prior to checking +the MAC. By using an independently-keyed cipher instance to encrypt the +length, an active attacker seeking to exploit the packet input handling +as a decryption oracle can learn nothing about the payload contents or +its MAC (assuming key derivation is secure). + +The AEAD is constructed as follows: for each packet, generate a Poly1305 +key by taking the first 256 bits of ChaCha20 stream output generated +using K_2, an IV consisting of the packet sequence number encoded as an +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of +zero. The K_2 ChaCha20 block counter is then set to the little-endian +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used +for encryption of the packet payload. + +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_1 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 with the one appended to the packet and the packet +decrypted using ChaCha20 as described above (with K_2, 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_1. Encrypt the packet payload (using K_2) and append it to the +encrypted length. Finally, calculate a MAC tag and append it. + +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 rekeying every 1GB of data +sent or received. If this recommendation is followed, then +chacha20-poly1305 at openssh.com requires no special handling in this area. + +References +---------- + +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein + http://cr.yp.to/chacha/chacha-20080128.pdf + +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein + http://cr.yp.to/mac/poly1305-20050329.pdf + +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 + +$OpenBSD$ + Index: usr.bin/ssh/authfile.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/authfile.c,v retrieving revision 1.97 diff -u -p -r1.97 authfile.c --- usr.bin/ssh/authfile.c 17 May 2013 00:13:13 -0000 1.97 +++ usr.bin/ssh/authfile.c 17 Nov 2013 13:57:29 -0000 @@ -144,7 +144,7 @@ key_private_rsa1_to_blob(Key *key, Buffe cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_ENCRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); @@ -462,7 +462,7 @@ key_parse_private_rsa1(Buffer *blob, con /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(©), buffer_len(©), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); Index: usr.bin/ssh/chacha.c =================================================================== RCS file: usr.bin/ssh/chacha.c diff -N usr.bin/ssh/chacha.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ssh/chacha.c 17 Nov 2013 13:57:29 -0000 @@ -0,0 +1,217 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "chacha.h" + +/* $OpenBSD$ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct chacha_ctx chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) +{ + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} Index: usr.bin/ssh/chacha.h =================================================================== RCS file: usr.bin/ssh/chacha.h diff -N usr.bin/ssh/chacha.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ssh/chacha.h 17 Nov 2013 13:57:29 -0000 @@ -0,0 +1,35 @@ +/* $OpenBSD$ */ + +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_H +#define CHACHA_H + +#include + +struct chacha_ctx { + u_int input[16]; +}; + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, + u_char *c, u_int bytes) + __attribute__((__bounded__(__buffer__, 2, 4))) + __attribute__((__bounded__(__buffer__, 3, 4))); + +#endif /* CHACHA_H */ + Index: usr.bin/ssh/chacha20poly1305aead.c =================================================================== RCS file: usr.bin/ssh/chacha20poly1305aead.c diff -N usr.bin/ssh/chacha20poly1305aead.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ssh/chacha20poly1305aead.c 17 Nov 2013 13:57:30 -0000 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include /* needed for log.h */ +#include +#include /* needed for misc.h */ + +#include "log.h" +#include "misc.h" +#include "chacha20poly1305aead.h" + +void cp_aead_init(struct chacha_poly_aead_ctx *ctx, + const u_char *key, u_int keylen) +{ + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ + fatal("%s: invalid keylen %u", __func__, keylen); + chacha_keysetup(&ctx->main_ctx, key, 256); + chacha_keysetup(&ctx->header_ctx, key + 32, 256); +} + +/* + * cp_aead_crypt() operates as following: + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. + * Theses bytes are treated as additional authenticated data. + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the + * authentication tag. + * This tag is written on encryption and verified on decryption. + * Both 'aadlen' and 'authlen' can be set to 0. + */ +int +cp_aead_crypt(struct chacha_poly_aead_ctx *ctx, u_int seqnr, u_char *dest, + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) +{ + u_char seqbuf[8]; + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; + int r = -1; + + /* + * Run ChaCha20 once to generate the Poly1305 key. The IV is the + * packet sequence number. + */ + bzero(poly_key, sizeof(poly_key)); + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->main_ctx, + poly_key, poly_key, sizeof(poly_key)); + /* Set Chacha's block counter to 1 */ + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); + + /* If decrypting, check tag before anything else */ + if (!do_encrypt) { + const u_char *tag = src + aadlen + len; + + poly1305_auth(expected_tag, src, aadlen + len, poly_key); + if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) + goto out; + } + /* Crypt additional data */ + if (aadlen) { + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); + } + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, + dest + aadlen, len); + + /* If encrypting, calculate and append tag */ + if (do_encrypt) { + poly1305_auth(dest + aadlen + len, dest, aadlen + len, + poly_key); + } + r = 0; + + out: + bzero(expected_tag, sizeof(expected_tag)); + bzero(seqbuf, sizeof(seqbuf)); + bzero(poly_key, sizeof(poly_key)); + return r; +} + +int +cp_aead_get_length(struct chacha_poly_aead_ctx *ctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) +{ + u_char buf[4], seqbuf[8]; + + if (len < 4) + return -1; /* Insufficient length */ + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); + *plenp = get_u32(buf); + return 0; +} + Index: usr.bin/ssh/chacha20poly1305aead.h =================================================================== RCS file: usr.bin/ssh/chacha20poly1305aead.h diff -N usr.bin/ssh/chacha20poly1305aead.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ssh/chacha20poly1305aead.h 17 Nov 2013 13:57:30 -0000 @@ -0,0 +1,41 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) Damien Miller 2013 + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef CHACHA_POLY_AEAD_H +#define CHACHA_POLY_AEAD_H + +#include +#include "chacha.h" +#include "poly1305-donna-unrolled.h" + +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ + +struct chacha_poly_aead_ctx { + struct chacha_ctx main_ctx, header_ctx; +}; + +void cp_aead_init(struct chacha_poly_aead_ctx *cpctx, + const u_char *key, u_int keylen) + __attribute__((__bounded__(__buffer__, 2, 3))); +int cp_aead_crypt(struct chacha_poly_aead_ctx *cpctx, u_int seqnr, + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, + int do_encrypt); +int cp_aead_get_length(struct chacha_poly_aead_ctx *cpctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) + __attribute__((__bounded__(__buffer__, 4, 5))); + +#endif /* CHACHA_POLY_AEAD_H */ Index: usr.bin/ssh/cipher.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/cipher.c,v retrieving revision 1.90 diff -u -p -r1.90 cipher.c --- usr.bin/ssh/cipher.c 7 Nov 2013 11:58:27 -0000 1.90 +++ usr.bin/ssh/cipher.c 17 Nov 2013 13:57:30 -0000 @@ -41,9 +41,11 @@ #include #include +#include #include "xmalloc.h" #include "log.h" +#include "misc.h" #include "cipher.h" extern const EVP_CIPHER *evp_ssh1_bf(void); @@ -58,7 +60,9 @@ struct Cipher { u_int iv_len; /* defaults to block_size */ u_int auth_len; u_int discard_len; - u_int cbc_mode; + u_int flags; +#define CFLAG_CBC (1<<0) +#define CFLAG_CP_AEAD (1<<1) const EVP_CIPHER *(*evptype)(void); }; @@ -88,6 +92,8 @@ static const struct Cipher ciphers[] = { SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, { "aes256-gcm at openssh.com", SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, + { "chacha20-poly1305 at openssh.com", + SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CP_AEAD, NULL }, { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } }; @@ -96,7 +102,7 @@ static const struct Cipher ciphers[] = { /* Returns a list of supported ciphers separated by the specified char. */ char * -cipher_alg_list(char sep) +cipher_alg_list(char sep, int auth_only) { char *ret = NULL; size_t nlen, rlen = 0; @@ -105,6 +111,8 @@ cipher_alg_list(char sep) for (c = ciphers; c->name != NULL; c++) { if (c->number != SSH_CIPHER_SSH2) continue; + if (auth_only && c->auth_len == 0) + continue; if (ret != NULL) ret[rlen++] = sep; nlen = strlen(c->name); @@ -136,7 +144,12 @@ cipher_authlen(const Cipher *c) u_int cipher_ivlen(const Cipher *c) { - return (c->iv_len ? c->iv_len : c->block_size); + /* + * Default is cipher block size, except for chacha20+poly1305 that + * needs no IV. XXX make iv_len == -1 default? + */ + return (c->iv_len != 0 || (c->flags & CFLAG_CP_AEAD) != 0) ? + c->iv_len : c->block_size; } u_int @@ -148,7 +161,7 @@ cipher_get_number(const Cipher *c) u_int cipher_is_cbc(const Cipher *c) { - return (c->cbc_mode); + return (c->flags & CFLAG_CBC) != 0; } u_int @@ -264,8 +277,11 @@ cipher_init(CipherContext *cc, const Cip ivlen, cipher->name); cc->cipher = cipher; + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + cp_aead_init(&cc->cp_ctx, key, keylen); + return; + } type = (*cipher->evptype)(); - EVP_CIPHER_CTX_init(&cc->evp); if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, (do_encrypt == CIPHER_ENCRYPT)) == 0) @@ -310,9 +326,15 @@ cipher_init(CipherContext *cc, const Cip * Both 'aadlen' and 'authlen' can be set to 0. */ void -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen) { + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + if (cp_aead_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, + authlen, cc->encrypt) != 0) + fatal("Decryption integrity check failed"); + return; + } if (authlen) { u_char lastiv[1]; @@ -354,10 +376,29 @@ cipher_crypt(CipherContext *cc, u_char * } } +/* + * Extract the packet length for an AEAD cipher, including any decryption + * necessary beforehand. + */ +int +cipher_aead_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, + const u_char *cp, u_int len) +{ + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + return cp_aead_get_length(&cc->cp_ctx, plenp, seqnr, + cp, len); + if (len < 4) + return -1; + *plenp = get_u32(cp); + return 0; +} + void cipher_cleanup(CipherContext *cc) { - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); } @@ -397,6 +438,8 @@ cipher_get_keyiv_len(const CipherContext if (c->number == SSH_CIPHER_3DES) ivlen = 24; + else if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + ivlen = 0; else ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); return (ivlen); @@ -408,6 +451,12 @@ cipher_get_keyiv(CipherContext *cc, u_ch const Cipher *c = cc->cipher; int evplen; + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) { + if (len != 0) + fatal("%s: wrong iv length %d != %d", __func__, len, 0); + return; + } + switch (c->number) { case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: @@ -438,6 +487,9 @@ cipher_set_keyiv(CipherContext *cc, u_ch { const Cipher *c = cc->cipher; int evplen = 0; + + if ((cc->cipher->flags & CFLAG_CP_AEAD) != 0) + return; switch (c->number) { case SSH_CIPHER_SSH2: Index: usr.bin/ssh/cipher.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/cipher.h,v retrieving revision 1.41 diff -u -p -r1.41 cipher.h --- usr.bin/ssh/cipher.h 7 Nov 2013 11:58:27 -0000 1.41 +++ usr.bin/ssh/cipher.h 17 Nov 2013 13:57:30 -0000 @@ -38,6 +38,8 @@ #define CIPHER_H #include +#include "chacha20poly1305aead.h" + /* * Cipher types for SSH-1. New types can be added, but old types should not * be removed for compatibility. The maximum allowed value is 31. @@ -65,7 +67,9 @@ struct Cipher; struct CipherContext { int plaintext; int encrypt; + int is_cp_aead; EVP_CIPHER_CTX evp; + struct chacha_poly_aead_ctx cp_ctx; /* XXX union with evp? */ const Cipher *cipher; }; @@ -75,11 +79,13 @@ const Cipher *cipher_by_number(int); int cipher_number(const char *); char *cipher_name(int); int ciphers_valid(const char *); -char *cipher_alg_list(char); +char *cipher_alg_list(char, int); void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, const u_char *, u_int, int); -void cipher_crypt(CipherContext *, u_char *, const u_char *, +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, u_int, u_int, u_int); +int cipher_aead_get_length(CipherContext *, u_int *, u_int, + const u_char *, u_int); void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); u_int cipher_blocksize(const Cipher *); Index: usr.bin/ssh/myproposal.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/myproposal.h,v retrieving revision 1.33 diff -u -p -r1.33 myproposal.h --- usr.bin/ssh/myproposal.h 2 Nov 2013 21:59:15 -0000 1.33 +++ usr.bin/ssh/myproposal.h 17 Nov 2013 13:57:30 -0000 @@ -52,6 +52,7 @@ "aes128-ctr,aes192-ctr,aes256-ctr," \ "arcfour256,arcfour128," \ "aes128-gcm at openssh.com,aes256-gcm at openssh.com," \ + "chacha20-poly1305 at openssh.com," \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc at lysator.liu.se" #define KEX_DEFAULT_MAC \ Index: usr.bin/ssh/packet.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/packet.c,v retrieving revision 1.189 diff -u -p -r1.189 packet.c --- usr.bin/ssh/packet.c 8 Nov 2013 00:39:15 -0000 1.189 +++ usr.bin/ssh/packet.c 17 Nov 2013 13:57:30 -0000 @@ -702,7 +702,7 @@ packet_send1(void) buffer_append(&active_state->output, buf, 4); cp = buffer_append_space(&active_state->output, buffer_len(&active_state->outgoing_packet)); - cipher_crypt(&active_state->send_context, cp, + cipher_crypt(&active_state->send_context, 0, cp, buffer_ptr(&active_state->outgoing_packet), buffer_len(&active_state->outgoing_packet), 0, 0); @@ -935,8 +935,8 @@ packet_send2_wrapped(void) } /* encrypt packet and append to output buffer. */ cp = buffer_append_space(&active_state->output, len + authlen); - cipher_crypt(&active_state->send_context, cp, - buffer_ptr(&active_state->outgoing_packet), + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, + cp, buffer_ptr(&active_state->outgoing_packet), len - aadlen, aadlen, authlen); /* append unencrypted MAC */ if (mac && mac->enabled) { @@ -1196,7 +1196,7 @@ packet_read_poll1(void) /* Decrypt data to incoming_packet. */ buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, padded_len); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, 0, cp, buffer_ptr(&active_state->input), padded_len, 0, 0); buffer_consume(&active_state->input, padded_len); @@ -1267,10 +1267,12 @@ packet_read_poll2(u_int32_t *seqnr_p) aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; if (aadlen && active_state->packlen == 0) { - if (buffer_len(&active_state->input) < 4) + if (cipher_aead_get_length(&active_state->receive_context, + &active_state->packlen, + active_state->p_read.seqnr, + buffer_ptr(&active_state->input), + buffer_len(&active_state->input)) != 0) return SSH_MSG_NONE; - cp = buffer_ptr(&active_state->input); - active_state->packlen = get_u32(cp); if (active_state->packlen < 1 + 4 || active_state->packlen > PACKET_MAX_SIZE) { #ifdef PACKET_DEBUG @@ -1290,7 +1292,8 @@ packet_read_poll2(u_int32_t *seqnr_p) buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, block_size); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), block_size, 0, 0); cp = buffer_ptr(&active_state->incoming_packet); active_state->packlen = get_u32(cp); @@ -1345,7 +1348,8 @@ packet_read_poll2(u_int32_t *seqnr_p) macbuf = mac_compute(mac, active_state->p_read.seqnr, buffer_ptr(&active_state->input), aadlen + need); cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), need, aadlen, authlen); buffer_consume(&active_state->input, aadlen + need + authlen); /* Index: usr.bin/ssh/poly1305-donna-unrolled.c =================================================================== RCS file: usr.bin/ssh/poly1305-donna-unrolled.c diff -N usr.bin/ssh/poly1305-donna-unrolled.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ssh/poly1305-donna-unrolled.c 17 Nov 2013 13:57:30 -0000 @@ -0,0 +1,154 @@ +/* + * Public Domain poly1305-donna from Andrew M. + * https://github.com/floodyberry/poly1305-donna + */ + +#include +#include + +#include "poly1305-donna-unrolled.h" + +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) + +#define U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LE(p, v) \ + do { \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); \ + } while (0) + +void +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { + uint32_t t0,t1,t2,t3; + uint32_t h0,h1,h2,h3,h4; + uint32_t r0,r1,r2,r3,r4; + uint32_t s1,s2,s3,s4; + uint32_t b, nb; + size_t j; + uint64_t t[5]; + uint64_t f0,f1,f2,f3; + uint32_t g0,g1,g2,g3,g4; + uint64_t c; + unsigned char mp[16]; + + /* clamp key */ + t0 = U8TO32_LE(key+0); + t1 = U8TO32_LE(key+4); + t2 = U8TO32_LE(key+8); + t3 = U8TO32_LE(key+12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (inlen < 16) goto poly1305_donna_atmost15bytes; +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = U8TO32_LE(m-16); + t1 = U8TO32_LE(m-12); + t2 = U8TO32_LE(m-8); + t3 = U8TO32_LE(m-4); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8) | (1 << 24); + + +poly1305_donna_mul: + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); + h0 += b * 5; + + if (inlen >= 16) goto poly1305_donna_16bytes; + + /* final bytes */ +poly1305_donna_atmost15bytes: + if (!inlen) goto poly1305_donna_finish; + + for (j = 0; j < inlen; j++) mp[j] = m[j]; + mp[j++] = 1; + for (; j < 16; j++) mp[j] = 0; + inlen = 0; + + t0 = U8TO32_LE(mp+0); + t1 = U8TO32_LE(mp+4); + t2 = U8TO32_LE(mp+8); + t3 = U8TO32_LE(mp+12); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); + + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); + U32TO8_LE(&out[12], f3); +} Index: usr.bin/ssh/poly1305-donna-unrolled.h =================================================================== RCS file: usr.bin/ssh/poly1305-donna-unrolled.h diff -N usr.bin/ssh/poly1305-donna-unrolled.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/ssh/poly1305-donna-unrolled.h 17 Nov 2013 13:57:30 -0000 @@ -0,0 +1,22 @@ +/* $OpenBSD$ */ + +/* + * Public Domain poly1305-donna from Andrew M. + * https://github.com/floodyberry/poly1305-donna + */ + +#ifndef POLY1305_H +#define POLY1305_H + +#include + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, + const u_char key[POLY1305_KEYLEN]) + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) + __attribute__((__bounded__(__buffer__, 2, 3))) + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); + +#endif /* POLY1305_H */ Index: usr.bin/ssh/servconf.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/servconf.c,v retrieving revision 1.245 diff -u -p -r1.245 servconf.c --- usr.bin/ssh/servconf.c 7 Nov 2013 11:58:27 -0000 1.245 +++ usr.bin/ssh/servconf.c 17 Nov 2013 13:57:30 -0000 @@ -1986,7 +1986,7 @@ dump_config(ServerOptions *o) dump_cfg_string(sPidFile, o->pid_file); dump_cfg_string(sXAuthLocation, o->xauth_location); dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : - cipher_alg_list(',')); + cipher_alg_list(',', 0)); dump_cfg_string(sMacs, o->macs ? o->macs : mac_alg_list(',')); dump_cfg_string(sBanner, o->banner); dump_cfg_string(sForceCommand, o->adm_forced_command); Index: usr.bin/ssh/ssh.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/ssh.c,v retrieving revision 1.392 diff -u -p -r1.392 ssh.c --- usr.bin/ssh/ssh.c 7 Nov 2013 11:58:27 -0000 1.392 +++ usr.bin/ssh/ssh.c 17 Nov 2013 13:57:30 -0000 @@ -492,7 +492,9 @@ main(int ac, char **av) case 'Q': /* deprecated */ cp = NULL; if (strcasecmp(optarg, "cipher") == 0) - cp = cipher_alg_list('\n'); + cp = cipher_alg_list('\n', 0); + else if (strcasecmp(optarg, "cipher-auth") == 0) + cp = cipher_alg_list('\n', 1); else if (strcasecmp(optarg, "mac") == 0) cp = mac_alg_list('\n'); else if (strcasecmp(optarg, "kex") == 0) Index: usr.bin/ssh/lib/Makefile =================================================================== RCS file: /cvs/src/usr.bin/ssh/lib/Makefile,v retrieving revision 1.68 diff -u -p -r1.68 Makefile --- usr.bin/ssh/lib/Makefile 2 Nov 2013 21:59:15 -0000 1.68 +++ usr.bin/ssh/lib/Makefile 17 Nov 2013 13:57:30 -0000 @@ -13,7 +13,8 @@ SRCS= authfd.c authfile.c bufaux.c bufec ssh-dss.c ssh-rsa.c ssh-ecdsa.c dh.c kexdh.c kexgex.c kexecdh.c \ kexdhc.c kexgexc.c kexecdhc.c msg.c progressmeter.c dns.c \ monitor_fdpass.c umac.c addrmatch.c schnorr.c jpake.c ssh-pkcs11.c \ - krl.c smult_curve25519_ref.c kexc25519.c kexc25519c.c + krl.c smult_curve25519_ref.c kexc25519.c kexc25519c.c \ + chacha.c poly1305-donna-unrolled.c chacha20poly1305aead.c SRCS+= umac128.c CLEANFILES+= umac128.c Index: regress/usr.bin/ssh/integrity.sh =================================================================== RCS file: /cvs/src/regress/usr.bin/ssh/integrity.sh,v retrieving revision 1.11 diff -u -p -r1.11 integrity.sh --- regress/usr.bin/ssh/integrity.sh 7 Nov 2013 02:48:38 -0000 1.11 +++ regress/usr.bin/ssh/integrity.sh 17 Nov 2013 13:57:30 -0000 @@ -11,7 +11,7 @@ startoffset=2900 macs=`${SSH} -Q mac` # The following are not MACs, but ciphers with integrated integrity. They are # handled specially below. -macs="$macs `${SSH} -Q cipher | grep gcm at openssh.com`" +macs="$macs `${SSH} -Q cipher-auth`" # sshd-command for proxy (see test-exec.sh) cmd="sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSHD_LOGFILE} -i -f $OBJ/sshd_proxy" @@ -30,12 +30,14 @@ for m in $macs; do fi # modify output from sshd at offset $off pxy="proxycommand=$cmd | $OBJ/modpipe -wm xor:$off:1" - case $m in - aes*gcm*) macopt="-c $m";; - *) macopt="-m $m";; - esac + if ssh -Q cipher-auth | grep "^${m}\$" >/dev/null 2>&1 ; then + macopt="-c $m" + else + macopt="-m $m -c aes128-ctr" + fi verbose "test $tid: $m @$off" ${SSH} $macopt -2F $OBJ/ssh_proxy -o "$pxy" \ + -oServerAliveInterval=1 -oServerAliveCountMax=30 \ 999.999.999.999 'printf "%4096s" " "' >/dev/null if [ $? -eq 0 ]; then fail "ssh -m $m succeeds with bit-flip at $off" From cloos at jhcloos.com Mon Nov 18 02:57:32 2013 From: cloos at jhcloos.com (James Cloos) Date: Sun, 17 Nov 2013 10:57:32 -0500 Subject: chacha20+poly1305 authenticated encryption In-Reply-To: (Damien Miller's message of "Sun, 17 Nov 2013 14:35:34 +1100 (EST)") References: Message-ID: >>>>> "DM" == Damien Miller writes: DM> There is plenty of room for improvement Of course. DM> both the Poly1305 and ChaCha20 implementations in the patch DM> are plain C. I was impressed with the current speed for sysems which lack aesni. Those are still the most significant for me. DM> There are significantly faster versions available in DM> libnacl/libsodium. Experimenting with the code in libsodium was my next goal. DM> Once this code lands in OpenSSH, I'll probably add some way DM> to use these external libraries in portable OpenSSH. +1. On each box where I tested, make tests, once it completed, returned all tests passed. -JimC -- James Cloos OpenPGP: 1024D/ED7DAEA6 From naddy at mips.inka.de Mon Nov 18 09:36:02 2013 From: naddy at mips.inka.de (Christian Weisgerber) Date: Sun, 17 Nov 2013 22:36:02 +0000 (UTC) Subject: t-forward-control on slow machines Message-ID: On how slow a machine do we want the regression tests, specifically forward-control.sh, to still work? On my Alpha PC164 (21164-500, ~1997), the forward-control test produces erratic results. It eventually dawned on me that this is just a timing problem. Bumping the timeouts from 5 to 10s makes it run reliably. But then I'm sure Miod has even slower machines, so I don't know what we want to accommodate. Index: forward-control.sh =================================================================== RCS file: /cvs/src/regress/usr.bin/ssh/forward-control.sh,v retrieving revision 1.1 diff -u -p -r1.1 forward-control.sh --- forward-control.sh 2 Dec 2012 20:47:48 -0000 1.1 +++ forward-control.sh 17 Nov 2013 21:57:57 -0000 @@ -14,7 +14,7 @@ wait_for_file_to_appear() { while test ! -e $_path ; do test $_n -eq 1 && trace "waiting for $_path to appear" _n=`expr $_n + 1` - test $_n -ge 5 && return 1 + test $_n -ge 10 && return 1 sleep 1 done return 0 @@ -26,7 +26,7 @@ wait_for_process_to_exit() { while kill -0 $_pid 2>/dev/null ; do test $_n -eq 1 && trace "waiting for $_pid to exit" _n=`expr $_n + 1` - test $_n -ge 5 && return 1 + test $_n -ge 10 && return 1 sleep 1 done return 0 -- Christian "naddy" Weisgerber naddy at mips.inka.de From djm at mindrot.org Mon Nov 18 10:09:43 2013 From: djm at mindrot.org (Damien Miller) Date: Mon, 18 Nov 2013 10:09:43 +1100 (EST) Subject: Rekey regression test: How is GCM magical? In-Reply-To: <20131116195952.GA17218@lorvorc.mips.inka.de> References: <0C119CD9-D9CB-468B-9D5C-7B10D2198A12@gmail.com> <20131116195952.GA17218@lorvorc.mips.inka.de> Message-ID: On Sat, 16 Nov 2013, Christian Weisgerber wrote: > Markus Friedl: > > > > (chacha20-poly1305 doesn't work with diffie-hellman-group1-sha1 > > > because the latter can't provide the required 512 bits of key > > > material.) > > > > why should it not work? in this case the key gets expanded, > > even if the security margin of the kex is smaller. > > Well, it doesn't. > > $ ssh -c chacha20-poly1305 at openssh.com -oKexAlgorithms=diffie-hellman-group1-sha1 localhost > dh_gen_key: group too small: 1024 (2*need 1024) I think that check is incorrect (and could be simplified): Index: dh.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/dh.c,v retrieving revision 1.52 diff -u -p -r1.52 dh.c --- dh.c 8 Oct 2013 11:42:13 -0000 1.52 +++ dh.c 17 Nov 2013 23:08:38 -0000 @@ -257,7 +257,7 @@ dh_gen_key(DH *dh, int need) fatal("dh_gen_key: need < 0"); if (dh->p == NULL) fatal("dh_gen_key: dh->p == NULL"); - if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p)) + if (need > BN_num_bits(dh->p) / 2) fatal("dh_gen_key: group too small: %d (2*need %d)", BN_num_bits(dh->p), 2*need); do { From djm at mindrot.org Mon Nov 18 12:34:34 2013 From: djm at mindrot.org (Damien Miller) Date: Mon, 18 Nov 2013 12:34:34 +1100 (EST) Subject: t-forward-control on slow machines In-Reply-To: References: Message-ID: On Sun, 17 Nov 2013, Christian Weisgerber wrote: > On how slow a machine do we want the regression tests, specifically > forward-control.sh, to still work? > > On my Alpha PC164 (21164-500, ~1997), the forward-control test > produces erratic results. It eventually dawned on me that this is > just a timing problem. Bumping the timeouts from 5 to 10s makes > it run reliably. But then I'm sure Miod has even slower machines, > so I don't know what we want to accommodate. I think waiting 10s or longer is okay, since in the normal case we should never have to wait that long. I'd love a way to make this test work without polling, but I couldn't figure out how when I wrote the test. Your diff is ok djm@ -d From dtucker at zip.com.au Mon Nov 18 17:04:03 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Mon, 18 Nov 2013 01:04:03 -0500 Subject: t-forward-control on slow machines In-Reply-To: References: Message-ID: On Sun, Nov 17, 2013 at 5:36 PM, Christian Weisgerber wrote: > On how slow a machine do we want the regression tests, specifically > forward-control.sh, to still work? TL;DR all of them. Where possible we try to write the tests to work on any machine capable of running the software, eg by not coding a timeout.. Where that's not possible, increasing timeouts to be able to run the tests to run on any extant platform is entirely reasonable. The slowest thing I've personally tried recently is a 170MHz TurboSPARC, and that woked last time I tried,. -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From Peter.Reinig at keymile.com Tue Nov 19 01:07:52 2013 From: Peter.Reinig at keymile.com (Reinig, Peter) Date: Mon, 18 Nov 2013 15:07:52 +0100 Subject: Bug in openssh-6.4p1 Message-ID: Hello Guys, I found the following bug of openssh-6.4p1 using Solaris 10 in channels.c which results in scanning only AF_INET6 addresses for X11 forwarding. If the server has only AF_INET addresses, these are never tested and so X11 forwarding fails. The following diff shows a possible fix: user at server [openssh-6.4p1] diff -c channels.c* *** channels.c Mo Nov 18 14:36:51 2013 --- channels.c_orig Mo Nov 18 14:36:24 2013 *************** *** 3470,3476 **** close(socks[n]); } num_socks = 0; ! continue; } socks[num_socks++] = sock; if (num_socks == NUM_SOCKS) --- 3470,3476 ---- close(socks[n]); } num_socks = 0; ! break; } socks[num_socks++] = sock; if (num_socks == NUM_SOCKS) Regards , Peter Head of R&D Network Management Solutions KEYMILE Hanover ________________________________________ KEYMILE GmbH Wohlenbergstra?e 3 30179 Hannover Phone: +49 511 67 47-697 Fax: +49 511 67 47-777 E-mail: Peter.Reinig at keymile.com HTTP: http://www.keymile.com << KEYMILE: A Specialist as a Partner >> ********************************************************************************************************* Gesch?ftsf?hrer: Bj?rn Claa?en, Michael Breyer, Axel F?ry - Rechtsform der Gesellschaft: GmbH, Sitz: Hannover - HRB 61069, Amtsgericht Hannover; USt-Id. Nr.: DE 812282795; WEEE-Reg.-Nr.: DE 59336750 Managing Directors: Bjoern Claassen, Michael Breyer, Axel Foery - Legal structure: GmbH, Registered office: Hanover, HRB 61069 - Local court Hanover, VAT-Reg.-No.: DE 812282795, WEEE-Reg.-No.: DE 59336750 From djm at mindrot.org Tue Nov 19 11:27:08 2013 From: djm at mindrot.org (Damien Miller) Date: Tue, 19 Nov 2013 11:27:08 +1100 (EST) Subject: Projects for new developers Message-ID: Hi, A few people have asked about work they can do on OpenSSH that stands the chance of winning them a bug bounty from Google's program to reward open source security[1]. Some big things that we are missing relate to our test suite. Right now we don't have any automated way to run valgrind or AddressSanitizer and get good coverage. Some of the developers do this manually, and we do have some automatic detection of certain classes of memory faults when the regression suite is run on OpenBSD, but we really want more tools looking at the code with better coverage and on more platforms. So, if you want a project to work on you could: 1) Make a test suite (or modify our regression test suite) that runs the OpenSSH tools under valgrind, with good code/feature coverage and produces a useful summary report for each tool. 2) Same for AddressSanitizer 3) Port AddressSanitizer to OpenBSD so we can add it to the regress suite there. While this isn't OpenSSH directly, LLVM is now covered[2] by the bug bounty program and I'd be happy to make a statement of how this work has contributed to OpenSSH's security :) IMO any of these would make quite a difference to our proactive efforts to find bugs, particularly in the portable version. -d [1] http://googleonlinesecurity.blogspot.com.au/2013/10/going-beyond-vulnerability-rewards.html [2] http://googleonlinesecurity.blogspot.com.au/2013/11/even-more-patch-rewards.html From asn at cryptomilk.org Thu Nov 21 01:08:53 2013 From: asn at cryptomilk.org (Andreas Schneider) Date: Wed, 20 Nov 2013 15:08:53 +0100 Subject: Projects for new developers In-Reply-To: References: Message-ID: <33810494.IVCYAj5r9s@magrathea> On Tuesday 19 November 2013 11:27:08 Damien Miller wrote: > Hi, Hi, > So, if you want a project to work on you could: > > 1) Make a test suite (or modify our regression test suite) that runs > the OpenSSH tools under valgrind, with good code/feature coverage and > produces a useful summary report for each tool. in Samba we have several wrappers to test servers and clients. One of them is socket_wrapper which allows you to setup a fully isolated environment for testing! I've make them preloadable and it works very well. However it is still work in progress but maybe you want to take a look: http://git.cryptomilk.org/projects/socket_wrapper.git/tree/example/openssh.sh The plan is to use this to run libssh tests against openssh sshd or ssh against a libssh server. -- andreas -- Andreas Schneider GPG-ID: CC014E3D www.cryptomilk.org asn at cryptomilk.org From imorgan at nas.nasa.gov Thu Nov 21 06:50:27 2013 From: imorgan at nas.nasa.gov (Iain Morgan) Date: Wed, 20 Nov 2013 11:50:27 -0800 Subject: openssh-bugs mailing list archives Message-ID: <20131120195027.GE8747@linux124.nas.nasa.gov> Hello, Is there a problem with the openssh-bugs mailing list? I'm not subscribed to it, but watch the marc.info archive instead. The last message in the archive is the creation of bz#2163 on October 10th. The archive at gmane.org likewise seems to have stopped at the same time. I at first thought that this was just a lull in activity, but it's gone on rather long. Poking around at bugzilla.mindrot.org, I see that new bugs have been created since then, so this is obviously not the explanation. Is the list simply no longer being archived? -- Iain Morgan From dtucker at zip.com.au Thu Nov 21 09:34:14 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Wed, 20 Nov 2013 17:34:14 -0500 Subject: openssh-bugs mailing list archives In-Reply-To: <20131120195027.GE8747@linux124.nas.nasa.gov> References: <20131120195027.GE8747@linux124.nas.nasa.gov> Message-ID: On Wed, Nov 20, 2013 at 2:50 PM, Iain Morgan wrote: > Is there a problem with the openssh-bugs mailing list? I'm not > subscribed to it, but watch the marc.info archive instead. The list is certainlu working for me as a direct subscriber. I don't know what's happening with marc, but Damien keeps an current archive at http://lists.mindrot.org/pipermail/openssh-bugs -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From imorgan at nas.nasa.gov Thu Nov 21 09:41:23 2013 From: imorgan at nas.nasa.gov (Iain Morgan) Date: Wed, 20 Nov 2013 14:41:23 -0800 Subject: openssh-bugs mailing list archives In-Reply-To: References: <20131120195027.GE8747@linux124.nas.nasa.gov> Message-ID: <20131120224123.GB8715@linux124.nas.nasa.gov> On Wed, Nov 20, 2013 at 17:34:14 -0500, Darren Tucker wrote: > On Wed, Nov 20, 2013 at 2:50 PM, Iain Morgan wrote: > > Is there a problem with the openssh-bugs mailing list? I'm not > > subscribed to it, but watch the marc.info archive instead. > > The list is certainlu working for me as a direct subscriber. > > I don't know what's happening with marc, but Damien keeps an current > archive at http://lists.mindrot.org/pipermail/openssh-bugs > Hmm, that archive also stopped at the same point. -- Iain Morgan From djm at mindrot.org Thu Nov 21 10:15:51 2013 From: djm at mindrot.org (Damien Miller) Date: Thu, 21 Nov 2013 10:15:51 +1100 (EST) Subject: openssh-bugs mailing list archives In-Reply-To: <20131120195027.GE8747@linux124.nas.nasa.gov> References: <20131120195027.GE8747@linux124.nas.nasa.gov> Message-ID: On Wed, 20 Nov 2013, Iain Morgan wrote: > Hello, > > Is there a problem with the openssh-bugs mailing list? I'm not > subscribed to it, but watch the marc.info archive instead. The last > message in the archive is the creation of bz#2163 on October 10th. The > archive at gmane.org likewise seems to have stopped at the same time. > > I at first thought that this was just a lull in activity, but it's gone > on rather long. Poking around at bugzilla.mindrot.org, I see that new > bugs have been created since then, so this is obviously not the > explanation. > > Is the list simply no longer being archived? No, but a security upgrade brought with it some new behaviour that broke the archive. I've just fixed it, so new messages will be recorded properly. Unfortunately, I'm not sure of any easy way to get the ones missed over the last month added. -d From imorgan at nas.nasa.gov Thu Nov 21 11:17:43 2013 From: imorgan at nas.nasa.gov (Iain Morgan) Date: Wed, 20 Nov 2013 16:17:43 -0800 Subject: openssh-bugs mailing list archives In-Reply-To: References: <20131120195027.GE8747@linux124.nas.nasa.gov> Message-ID: <20131121001743.GC8715@linux124.nas.nasa.gov> On Thu, Nov 21, 2013 at 10:15:51 +1100, Damien Miller wrote: > On Wed, 20 Nov 2013, Iain Morgan wrote: > > > Hello, > > > > Is there a problem with the openssh-bugs mailing list? I'm not > > subscribed to it, but watch the marc.info archive instead. The last > > message in the archive is the creation of bz#2163 on October 10th. The > > archive at gmane.org likewise seems to have stopped at the same time. > > > > I at first thought that this was just a lull in activity, but it's gone > > on rather long. Poking around at bugzilla.mindrot.org, I see that new > > bugs have been created since then, so this is obviously not the > > explanation. > > > > Is the list simply no longer being archived? > > No, but a security upgrade brought with it some new behaviour that > broke the archive. I've just fixed it, so new messages will be recorded > properly. Unfortunately, I'm not sure of any easy way to get the ones > missed over the last month added. > Thanks. I can dig in bugzilla to find some of what's changed in the interim. BTW: While digging around I decided to subscribe to openssh-commits@ and received a bounce when I tried to reply to the confirmation message: ... while talking to [130.102.96.2]: >>> DATA <<< 554 5.7.1 : Recipient address rejected: internal address 554 5.0.0 Service unavailable <<< 554 5.5.1 Error: no valid recipients -- Iain Morgan From djm at mindrot.org Thu Nov 21 14:48:35 2013 From: djm at mindrot.org (Damien Miller) Date: Thu, 21 Nov 2013 14:48:35 +1100 (EST) Subject: openssh-bugs mailing list archives In-Reply-To: <20131121001743.GC8715@linux124.nas.nasa.gov> References: <20131120195027.GE8747@linux124.nas.nasa.gov> <20131121001743.GC8715@linux124.nas.nasa.gov> Message-ID: On Wed, 20 Nov 2013, Iain Morgan wrote: > BTW: While digging around I decided to subscribe to openssh-commits@ and > received a bounce when I tried to reply to the confirmation message: > > ... while talking to [130.102.96.2]: > >>> DATA > <<< 554 5.7.1 : Recipient address > rejected: internal address > 554 5.0.0 Service unavailable > <<< 554 5.5.1 Error: no valid recipients Thanks for letting me know. This was collateral damage of some anti- spam stuff I implemented after a couple of spams made it through to one of the lists; I'd checked that I hadn't broken subscription on openssh-unix-dev@ but neglected to test the others :( -d From djm at mindrot.org Fri Nov 22 13:23:26 2013 From: djm at mindrot.org (Damien Miller) Date: Fri, 22 Nov 2013 13:23:26 +1100 (EST) Subject: chacha20+poly1305 authenticated encryption In-Reply-To: References: Message-ID: On Thu, 14 Nov 2013, Damien Miller wrote: > Hi, > > Here's a diff to implement ChaCha20+Poly1305 as an authenticated > encryption mode. [...] FYI this is committed and in today's snapshot. -d From remoteshaman.com at gmail.com Fri Nov 22 20:57:07 2013 From: remoteshaman.com at gmail.com (remoteshaman.com at gmail.com) Date: Fri, 22 Nov 2013 11:57:07 +0200 Subject: Memory leak in OpenSSH Server for Windows/Cygwi Message-ID: <1E90B827C13940E284981943C46DAA30@torbaf407ff5ef> Hello! Repeating the connection / disconnection to "OpenSSH Server for Windows" using FileZilla about 10 times we get a whole bunch of hung processes sshd.exe and sftp-server.exe: image As a result, we have a memory leak through "OpenSSH Server for Windows". Problem is seen only when using FileZilla, another version "OpenSSH for Windows 3.81p1-ninth July 2004" and continues to be present in the current versions of "OpenSSH for Windows". For more details for "Memory leak in OpenSSH Server for Windows/Cygwi" please read this post (screenshot attached to post): http://translate.google.com/translate?hl=en&sl=ru&tl=en&u=http%3A%2F%2Fwww.remoteshaman.com%2Findex.php%3Foption%3Dcom_kunena%26view%3Dtopic%26catid%3D21%26id%3D58%26Itemid%3D114%2373 From dtucker at zip.com.au Sat Nov 23 05:06:26 2013 From: dtucker at zip.com.au (Darren Tucker) Date: Fri, 22 Nov 2013 13:06:26 -0500 Subject: Memory leak in OpenSSH Server for Windows/Cygwi In-Reply-To: <1E90B827C13940E284981943C46DAA30@torbaf407ff5ef> References: <1E90B827C13940E284981943C46DAA30@torbaf407ff5ef> Message-ID: On Fri, Nov 22, 2013 at 4:57 AM, wrote: [...] > As a result, we have a memory leak through "OpenSSH Server for Windows". > Problem is seen only when using FileZilla, another version "OpenSSH for > Windows 3.81p1-ninth July 2004" and continues to be present in the current > versions of "OpenSSH for Windows". That's a third-party packaging of extremely old versions of OpenSSH and Cygwin. It's not supplied or supported by the OpenSSH team. It's been reported to cause problems with current versions of Windows. If you have problems with it please contact the suppliers of the package. I suggest installing a current version of Cygwin and its packaged version of OpenSSH, which is more likely to be supportable. -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. From sdaoden at gmail.com Tue Nov 26 00:28:22 2013 From: sdaoden at gmail.com (Steffen Daode Nurpmeso) Date: Mon, 25 Nov 2013 14:28:22 +0100 Subject: Last http://hg.mindrot.org/openssh commit is from 2013-06-11 Message-ID: <20131125132822.mf9QhLU1+nz40Tju8MDAJjFc@dietcurd.local> Hello, well it's | Rev: || 11096:745a39c852ab tip 11094:e34042dabbd8 | Auth: dtucker | Date: Tue, 11 Jun 2013 02:10:02 +0000 - (dtucker) [myproposal.h] Make the conditional algorithm support consistent and add some comments so it's clear what goes where. Note it was still advertised in the 6.3 release notes. Has it been replaced by a git(1) repository? :-)) Thank you, --steffen From djm at mindrot.org Tue Nov 26 11:23:37 2013 From: djm at mindrot.org (Damien Miller) Date: Tue, 26 Nov 2013 11:23:37 +1100 (EST) Subject: Last http://hg.mindrot.org/openssh commit is from 2013-06-11 In-Reply-To: <20131125132822.mf9QhLU1+nz40Tju8MDAJjFc@dietcurd.local> References: <20131125132822.mf9QhLU1+nz40Tju8MDAJjFc@dietcurd.local> Message-ID: On Mon, 25 Nov 2013, Steffen Daode Nurpmeso wrote: > Hello, > well it's > > | Rev: || 11096:745a39c852ab tip 11094:e34042dabbd8 > | Auth: dtucker > | Date: Tue, 11 Jun 2013 02:10:02 +0000 > > - (dtucker) [myproposal.h] Make the conditional algorithm support consistent > and add some comments so it's clear what goes where. > > Note it was still advertised in the 6.3 release notes. > Has it been replaced by a git(1) repository? :-)) "hg convert" seems to have stopped working for some reason - it no longer appears to be recognising changes. I think I'll just pull the hg repository and replace it with a git one. -d From irfaan_c at yahoo.com Tue Nov 26 19:26:12 2013 From: irfaan_c at yahoo.com (irfaan coonjah) Date: Tue, 26 Nov 2013 00:26:12 -0800 (PST) Subject: OpenSSH tunneling Message-ID: <1385454372.27025.YahooMailNeo@web142702.mail.bf1.yahoo.com> I am currently working with tunneling with openssh and I am looking for a help. I have been able to setup the tunnel properly in a LAN environment and?I am followed these steps:?http://bodhizazen.net/Tutorials/VPN-Over-SSH?? Attached is a topology of the lan environment. The tunnel works properly and ping is successful. I want to extend the scope of the VPN tunnel and to setup the tunnel between two remote PCs which are in two different locations.?I port-forwarded the public ip addresses to the private ip address of the pcs. Both PCs can ssh? each other but tunneling is not working. The tun0 interface on both server and client is up but traffic is not flowing through the tunnels. ++++++++++Phase 1+++++++++++ ? ??PC-A can ssh to PC-B --- ssh?root at 197.225.79.115 ??PC-B can ssh to PC-A --- ssh?root at 196.192.83.17 +++++++++++Phase 2++++++++++ ? ??Aim is to create a? tunnel between PC-A and PC-B ? Tunnel shows up but ping to remote tun0 interface is not successful. PC-A -server pc with public ip address(196.192.83.17),private ip(10.1.3.13) port-forwarding via 22(ssh) ??root at PCA:~# modprobe ipip ??root at PCA:~# ip tu ad tun1 mode ipip remote 197.225.79.115 ttl 64 dev eth0 ??root at PCA:~# ip ad ad dev tun1 10.0.0.1 peer?10.0.0.2/32 ??root at PCA:~# ip li se dev tun1 up ??root at PCA:~# ip tunnel show tun1 ??tun1: ip/ip? remote 197.225.79.115? local any? dev eth0? ttl 64? ? ??PCB -client pc with public ip address(197.225.79.115),private ip(192.168.1.6) port-forwarding via 22 (ssh) ??+++++PC-B; client: irfaan at ubuntu:~$ vi /etc/network/interfaces++++++ ??iface tun1 inet static ??pre-up ssh -i /root/.ssh/VPN -S /var/run/ssh-vpn-tunnel-control -M -f -w 0:0 196.192.83.17 true ??pre-up sleep 15 ? ??address 10.0.0.2 ??pointopoint 10.0.0.1 ??netmask 255.255.255.0 ? ??up route add -host 196.192.83.17 dev eth1 ??up route add default gw 10.0.0.1 dev tun1 ??up route del default gw 192.168.1.1 dev eth1 ? ??down route add default gw 192.168.1.1 dev eth1 ??down route del default gw 10.0.0.1 dev tun1 ??down route del -host 196.192.83.17? dev eth1 ? ??post-down ssh -i /root/.ssh/VPN -S /var/run/ssh-vpn-tunnel-control -O exit 196.192.83.17 irfaan at ubuntu:~$ sudo ip tu ad tun1 mode ipip local 192.168.1.6 remote 196.196.83.17 ttl 64 dev eth1 ??irfaan at ubuntu:~$ sudo ip ad ad dev tun1 10.0.0.2 peer?10.0.0.1/32 ??irfaan at ubuntu:~$ sudo ip li se dev tun1 up irfaan at ubuntu:~$ sudo ifup tun1 ??root at 196.192.83.17's password:? ??channel 0: open failed: administratively prohibited: open failed ??ssh stop/waiting ??ssh start/running, process 5232 ??irfaan at ubuntu:~$ ping 10.0.0.1 ??PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data. ??From 10.0.0.2 icmp_seq=1 Destination Host Unreachable ??From 10.0.0.2 icmp_seq=4 Destination Host Unreachable ? ??irfaan at ubuntu:~$ sudo ip tunnel del tun1 ??irfaan at ubuntu:~$ sudo modprobe ipip ??irfaan at ubuntu:~$ sudo ip tun ad tun1 mode ipip local 197.225.79.115 remote 196.192.83.17 ttl 64 dev eth1 ??irfaan at ubuntu:~$ sudo ip ad ad dev tun1 10.0.0.1 peer?10.0.0.2/32 ??irfaan at ubuntu:~$ ip li se dev tun1 up ??RTNETLINK answers: Operation not permitted ??irfaan at ubuntu:~$ sudo ip li se dev tun1 up ? ??irfaan at ubuntu:~$ sudo ifup tun1 ??root at 196.192.83.17's password:? ??channel 0: open failed: administratively prohibited: open failed ??ssh stop/waiting ??ssh start/running, process 6151 ??irfaan at ubuntu:~$ ping 10.0.0.1 ??PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data. ??From 10.0.0.2 icmp_seq=1 Destination Host Unreachable ??From 10.0.0.2 icmp_seq=2 Destination Host Unreachable ??^C ??--- 10.0.0.1 ping statistics --- ??2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 999ms ? ? ??Kind regards, ??Irfaan From djm at mindrot.org Tue Nov 26 19:37:21 2013 From: djm at mindrot.org (Damien Miller) Date: Tue, 26 Nov 2013 19:37:21 +1100 (EST) Subject: OpenSSH tunneling In-Reply-To: <1385454372.27025.YahooMailNeo@web142702.mail.bf1.yahoo.com> References: <1385454372.27025.YahooMailNeo@web142702.mail.bf1.yahoo.com> Message-ID: On Tue, 26 Nov 2013, irfaan coonjah wrote: > Both PCs can ssh each other but tunneling > is not working. The tun0 interface on both server and client is up but traffic > is not flowing through the tunnels. Have you enabled IP forwarding? > root at PCA:~# modprobe ipip > root at PCA:~# ip tu ad tun1 mode ipip remote > 197.225.79.115 ttl 64 dev eth0 I'm not sure why you are using IPIP. You should just be able to add a route through the tun0 interface to the remote network directly. > irfaan at ubuntu:~$ sudo ifup tun1 > root at 196.192.83.17's password: > channel > 0: open failed: administratively prohibited: open failed Your remote sshd is refusing the tunnel request. Is PermitTunnel set? -d From sdaoden at gmail.com Tue Nov 26 21:10:43 2013 From: sdaoden at gmail.com (Steffen Daode Nurpmeso) Date: Tue, 26 Nov 2013 11:10:43 +0100 Subject: Last http://hg.mindrot.org/openssh commit is from 2013-06-11 In-Reply-To: References: <20131125132822.mf9QhLU1+nz40Tju8MDAJjFc@dietcurd.local> Message-ID: <20131126101043.tTW9XmEXS7fomoedB1okZM1q@dietcurd.local> Damien Miller wrote: |"hg convert" seems to have stopped working for some reason - it no longer |appears to be recognising changes. I think I'll just pull the hg I don't know if it matters, but before asking the ML i searched and got a hit saying class 'mercurial.error.ParseError' - mindrot.org hg.mindrot.org/openssh/annotate/053b381724b8/acss.c A problem occurred in a Python script. Here is the sequence of function calls leading up to the error, in the order they occurred I can reproduce the search result via 'openssh mindrot mercurial error' (Google, from Germany). |appears to be recognising changes. I think I'll just pull the hg |repository and replace it with a git one. I would appreciate that -- it's ever so astonishing how easy revision control has become, even with fixups and heavy patch reordering, short-living branches and then garbage collection. All of this possibly not of real value for portable OpenSSH, though. |-d --steffen -------------- next part -------------- An embedded message was scrubbed... From: Damien Miller Subject: Re: Last http://hg.mindrot.org/openssh commit is from 2013-06-11 Date: Tue, 26 Nov 2013 11:23:37 +1100 (EST) Size: 3319 URL: