<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>This is probably not the site you are looking for</title>
    <description>No ads, no tracking. Ever.&lt;br/&gt; &lt;strong&gt;blog.stribik.technology&lt;/strong&gt; is completely static, without cookies or javascript.&lt;br/&gt; &lt;strong&gt;comments.stribik.technology&lt;/strong&gt; uses javascript and local storage, it's loaded when you click &quot;Show comments&quot;.
</description>
    <link>https://blog.stribik.technology/</link>
    <atom:link href="https://blog.stribik.technology/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Wed, 19 Apr 2023 17:46:03 +0000</pubDate>
    <lastBuildDate>Wed, 19 Apr 2023 17:46:03 +0000</lastBuildDate>
    <generator>Jekyll v3.9.3</generator>
    
      <item>
        <title>Service discovery and authentication</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://zookeeper.apache.org/&quot;&gt;ZooKeeper&lt;/a&gt; is a popular choice for service discovery in distributed systems.
It is a hierarchical key-value store with very strong consistency guarantees.
What makes it a good choice for service discovery is its capability to create temporary tree nodes that disappear when the session that created it is disconnected.
Another important feature is sequential nodes - nodes that have a consistent counter appended to their name.
You can use these for implementing distributed locking for example.
This post is about the authentication problems that appear as a result of introducting service discovery into a distributed system.&lt;/p&gt;

&lt;h1 id=&quot;service-discovery&quot;&gt;Service discovery&lt;/h1&gt;

&lt;p&gt;The exact details of implementing a &lt;a href=&quot;http://blog.arungupta.me/zookeeper-microservice-registration-discovery/&quot;&gt;service discovery protocol&lt;/a&gt; using ZooKeeper is outside the scope of this document.
I want to describe it in enough details so that we can understand its security properties.
Each service that’s running and ready to respond to requests opens a persistent connection to Zookeeper.
What usually happens is there is a root node, say /services, and it creates a temporary, sequential node:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
/services/foo-service-1 = https://somehost.inthecloud.internal:6666
/services/foo-service-3 = https://otherhost.inthecloud.internal:12345
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to talk to this foo-service, you look in this root node and retrieve all the registered foo-service hostnames.
You pick one randomly, or using round-robin, or what have you, and talk to that.
If it fails, you try another.
If you shut down foo-service, or it crashes, the temporary node is removed and other services will no longer try to talk to it.&lt;/p&gt;

&lt;h1 id=&quot;authenticating-hostnames&quot;&gt;Authenticating hostnames&lt;/h1&gt;

&lt;p&gt;In the example above, we are using HTTPS URLs, so you probably want some kind of internal CA to sign the certificates.
(You might want to use some different protocol, Kerberos maybe.)
You connect to the host and you can be sure it’s really that host, no one is eavesdropping, all the good things.&lt;/p&gt;

&lt;p&gt;There are two problems with this.
First, you are using Zookeeper because you don’t want to care about what host is running which service.
You certainly don’t want to sign a new certificate for each one, deploy the private key to that host, etc.
You can do this.
It is possible.
You can even automate it if you don’t mind having an online CA, that is not only easier to abuse, but also limits your availability.&lt;/p&gt;

&lt;p&gt;The second, and even more important problem is &lt;em&gt;authenticating the wrong thing&lt;/em&gt;.
What if ZooKeeper lies to you?
What if a compromised service publishes a hostname for some other service?
You connect to that, verify that its certificate is correct, and proceed talking to the wrong service without noticing anything is wrong.
Now, ZooKeeper is capable of controlling who can write what node, so you can create a structure like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
/services/foo-service/foo-service-1 = https://a.inthecloud.internal:6666
/services/foo-service/foo-service-3 = https://b.inthecloud.internal:12345
/services/bar-service/bar-service-0 = https://c.inthecloud.internal:6666
/services/baz-service/baz-service-2 = https://d.inthecloud.internal:4444
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You have to set up the permissions so that no one can write /services, the user running foo-service can only write /services/foo-service, etc.
This still doesn’t help if Zookeeper itself is compromised.&lt;/p&gt;

&lt;p&gt;This way we must trust Zookeeper and the CA.&lt;/p&gt;

&lt;h1 id=&quot;authenticating-service-names&quot;&gt;Authenticating service names&lt;/h1&gt;

&lt;p&gt;There is a better way.
We don’t care about the hostname, the same way we don’t care about the IP address.
We don’t sign certificates for IP addresses.
We can sign a certificate for the service name, as in, CN=foo-service.
Actually, we don’t even have to sign it - the (self-signed) certificate can be included with the code of its clients.&lt;/p&gt;

&lt;p&gt;The main disadvantage of this approach is having to write custom certificate validation code, which I have done in Java.
In Java it’s actually pretty simple, the interfaces of interest are &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/X509KeyManager.html&quot;&gt;X509KeyManager&lt;/a&gt; and &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/X509TrustManager.html&quot;&gt;X509TrustManager&lt;/a&gt;.
Some of the methods relating to CAs will be simple stubs.
There are “extended” versions of both, with more methods you don’t need.
I will publish the code, but I did this at work, and have not had time to reimplement it in the public domain.&lt;/p&gt;

&lt;p&gt;This way we don’t have to trust Zookeeper, and we don’t have to trust the CA either (we don’t have one).
The only thing we do have to trust is that the certificates included in the code are correct, but if someone can change that, they can change the code too.&lt;/p&gt;

&lt;p&gt;There is still the matter of deploying the private keys to the hosts, but now it can be the same one for each instance of the same service.
This could be on a NAS, or scp’d to the local machine before starting the service that needs it.
Obviously we also have to trust that the ACLs will protect the private key but this is no worse than the previous method.&lt;/p&gt;

&lt;h1 id=&quot;authenticating-the-client&quot;&gt;Authenticating the client&lt;/h1&gt;

&lt;p&gt;We must not forget to authenticate the client certificate as well.
This is usually not done for browsers, but for inter-service traffic it is essential.
You might want to use a different CN if the same service is sometimes the server and sometimes the client.
Or you can use the same certificate but I don’t recommend it.
If they are different you can use the CA system for client authentication and use the embedded cert system for server authentication.
Either way, this means you have to embedd the certificate of the client in the server code.&lt;/p&gt;

&lt;p&gt;There are all these certificates embedded everywhere.
It doesn’t sound too maintainable, but what’s really going on here is each service consists of 3 files:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A server JAR that runs the server and doesn’t contain any certs.&lt;/li&gt;
  &lt;li&gt;A client JAR that’s a library imported by the clients, and contains the cert for the service.&lt;/li&gt;
  &lt;li&gt;A certificate, to be used for client authentication. (Or not, you could use a CA here.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not that bad.&lt;/p&gt;

</description>
        <pubDate>Mon, 23 Nov 2015 00:00:00 +0000</pubDate>
        <link>https://blog.stribik.technology/2015/11/23/service-discovery-and-authentication.html</link>
        <guid isPermaLink="true">https://blog.stribik.technology/2015/11/23/service-discovery-and-authentication.html</guid>
        
        <category>java</category>
        
        <category>security</category>
        
        <category>zookeeper</category>
        
        <category>tls</category>
        
        
      </item>
    
      <item>
        <title>Why cyber deterrence is bullshit</title>
        <description>&lt;p&gt;You may have heard of &lt;a href=&quot;https://uk.businessinsider.com/us-retaliation-against-china-for-opm-hacks-2015-8&quot;&gt;this brilliant idea&lt;/a&gt;.
That’s right, “hack back” as foreign policy.
It does not and will never work.&lt;/p&gt;

&lt;p&gt;The reasons why this is utter bullshit should be all too obvious, but my Twitter account is locked and I have nothing better to do, so here goes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;The word cyber.&lt;/em&gt;
Whenever you hear it, question the speaker’s competence.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Easy access.&lt;/em&gt;
To build nuclear weapons, you need: relatively rare fissionable materials, huge enrichment facilities, knowledge, and ICBMs.
To hack, you need: a computer, electricity, knowledge, and Internet access.
You may be able to deter a few rational entities capable of building nukes, but not every single child capable of hacking OPM.
There is nothing even close to perfect rationality on the Internet.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Attribution.&lt;/em&gt;
Radars and satellites can clearly show where the missiles are coming from.
No such device exists for detecting the origin of a breach.
Attribution is purely guesswork, based on things like the language of strings found in the malware, source IPs, etc.
It’s like sending a postcard, then trying to figure out who read it.
Does that sound like perfect detection?&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Working defense.&lt;/em&gt;
Missile defense systems are actually more dangerous that the nukes they are trying to defend against.
This is because they have a &lt;a href=&quot;https://en.wikipedia.org/wiki/Pre-emptive_nuclear_strike#Destabilizing_role_of_missile_defense&quot;&gt;very interesting property&lt;/a&gt;:
They reduce the second strike capability of one side, making counterforce first strike the logical choice for the other.
The reason we are still all here, reading this post, is because covering large areas with such defenses is not feasible.
This is not the case for defending computers against intrusion.
Yes, attackers have a clear advantage over defenders, that is to say, hacking will always be possible.
But it is significantly more difficult, and the effect less devastating, if the opponent just doesn’t have an OPM equivalent.
There goes your second strike.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;It is not a fucking weapon.&lt;/em&gt;
The damage caused by even the worst breaches is nowhere near the damage caused by a thermonuclear explosion.
Even conventional weapons cause more damage, and are more scary.
This is also supported by the fact that no sane person would risk armed conflict over hacking incidents.
No one is afraid of getting pwned.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Today’s attackers don’t even need their advantage.
They get in because we let them.
We should focus on exploit mitigation (Grsecurity), isolation (Qubes), sandboxed multiprocess architectures (Chrome, qmail), encryption, and fixing shit.
Instead we are wasting time trying to make the attribution dice work, listening to fumbling idiots threaten the Chinese, and looking for a magic security device that solves everything if we just connect it to the network.&lt;/p&gt;

&lt;p&gt;We know what to do and we know how to do it.&lt;/p&gt;
</description>
        <pubDate>Fri, 07 Aug 2015 00:00:00 +0000</pubDate>
        <link>https://blog.stribik.technology/2015/08/07/why-cyber-deterrence-is-bullshit.html</link>
        <guid isPermaLink="true">https://blog.stribik.technology/2015/08/07/why-cyber-deterrence-is-bullshit.html</guid>
        
        <category>bullshit</category>
        
        <category>cybercybercyber</category>
        
        <category>deterrence</category>
        
        
      </item>
    
      <item>
        <title>Rowhammering ElGamal</title>
        <description>&lt;p&gt;I had this idea of combining a new hardware attack with an old cryptanalysis paper.
Specifically, using &lt;a href=&quot;http://www.rowhammer.com/&quot;&gt;Rowhammer&lt;/a&gt; to flip bits in an ElGamal private key.
The usual approach is to target executable memory or the page table and hope for a change that makes the system exploitable.
I’m guessing this is not going to be stable because you need a change in particular and other changes may crash things.
But we’ll see when Google releases their Chrome sandbox escape/kernel mode code execution details.
The attack described in &lt;a href=&quot;http://link.springer.com/chapter/10.1007/11556985_43?no-access=true&quot;&gt;Fault Cryptanalysis of ElGamal Signature Scheme&lt;/a&gt; results in key recovery for &lt;em&gt;any&lt;/em&gt; change in the private key.&lt;/p&gt;

&lt;h1 id=&quot;elgamal-signatures&quot;&gt;ElGamal signatures&lt;/h1&gt;

&lt;p&gt;Just a quick reminder on how &lt;a href=&quot;https://en.wikipedia.org/wiki/ElGamal_signature_scheme&quot;&gt;ElGamal&lt;/a&gt; works.
Nothing new here, feel free to skip ahead to the attack.
It’s an asymmetric signature scheme based on the Discrete Logarithm Problem.&lt;/p&gt;

&lt;p&gt;A large prime number, p, and a generator, g, defines a multiplicative group.
Choose a random integer, 1 &amp;lt; a &amp;lt; p - 2, as the private key, then compute the public key as y = g&lt;sup&gt;a&lt;/sup&gt; mod p.&lt;/p&gt;

&lt;p&gt;Normally signing works like so (m is the message to be signed):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Choose a random integer unique for each signature, 1 &amp;lt; k &amp;lt; p, so that k and p - 1 are relative primes.&lt;/li&gt;
  &lt;li&gt;r = g&lt;sup&gt;k&lt;/sup&gt; mod p&lt;/li&gt;
  &lt;li&gt;s = k&lt;sup&gt;-1&lt;/sup&gt; * (hash(m) - a * r) mod (p - 1)&lt;/li&gt;
  &lt;li&gt;If s == 0, then goto 1.&lt;/li&gt;
  &lt;li&gt;The pair (r, s) is the signature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verification looks kind of weird at first glance:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Check that 0 &amp;lt; r &amp;lt; p.&lt;/li&gt;
  &lt;li&gt;Check that 0 &amp;lt; s &amp;lt; p - 1.&lt;/li&gt;
  &lt;li&gt;Verify that g&lt;sup&gt;hash(m)&lt;/sup&gt; = y&lt;sup&gt;r&lt;/sup&gt; * r&lt;sup&gt;s&lt;/sup&gt; mod p&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But why? Solve the equation in step 3 of signing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;hash(m) = a * r + s * k mod (p - 1)&lt;/li&gt;
  &lt;li&gt;g&lt;sup&gt;hash(m)&lt;/sup&gt; = g&lt;sup&gt;a * r&lt;/sup&gt; * g&lt;sup&gt;s * k&lt;/sup&gt; mod p&lt;/li&gt;
  &lt;li&gt;g&lt;sup&gt;hash(m)&lt;/sup&gt; = y&lt;sup&gt;r&lt;/sup&gt; * r&lt;sup&gt;s&lt;/sup&gt; mod p&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hey, how is that mod p, not mod (p - 1)?
It’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Fermat%27s_little_theorem#Generalizations&quot;&gt;Fermat’s&lt;/a&gt; fault.&lt;/p&gt;

&lt;h1 id=&quot;fault-cryptanalysis-attack&quot;&gt;Fault cryptanalysis attack&lt;/h1&gt;

&lt;p&gt;If &lt;em&gt;for some reason&lt;/em&gt; one of the secret key bits gets flipped in memory, then an incorrect signature is computed.
Not only will this signature fail to verify, it reveals the original value of the flipped bit.
Since the original paper is behind a paywall I repeat some of the results here.&lt;/p&gt;

&lt;p&gt;A single bit error at the i-th bit of the secret key can be expressed as&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;a’ = a ± 2&lt;sup&gt;i&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This will result in an incorrect s:&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;s’ = k&lt;sup&gt;-1&lt;/sup&gt; * (hash(m) - a’ * r) mod (p - 1)&lt;/p&gt;

&lt;p&gt;From the incorrect signature (r, s’) the attacker can calculate r&lt;sup&gt;s’&lt;/sup&gt;.
Let’s see why that’s a problem.&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;r&lt;sup&gt;s’&lt;/sup&gt; = (g&lt;sup&gt;k&lt;/sup&gt;)&lt;sup&gt;k&lt;sup&gt;-1&lt;/sup&gt; * (hash(m) - a’ * r)&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;r&lt;sup&gt;s’&lt;/sup&gt; = g&lt;sup&gt;k * k&lt;sup&gt;-1&lt;/sup&gt; * (hash(m) - a’ * r)&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p&gt;k * k&lt;sup&gt;-1&lt;/sup&gt; is of course 1.&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;r&lt;sup&gt;s’&lt;/sup&gt; = g&lt;sup&gt;hash(m) - r * a’&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p&gt;Substituting a’ we get:&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;r&lt;sup&gt;s’&lt;/sup&gt; = g&lt;sup&gt;hash(m) - r * (a ± 2&lt;sup&gt;i&lt;/sup&gt;)&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;r&lt;sup&gt;s’&lt;/sup&gt; = g&lt;sup&gt;hash(m) - r * a ∓ r * 2&lt;sup&gt;i&lt;/sup&gt;&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;r&lt;sup&gt;s’&lt;/sup&gt; = g&lt;sup&gt;hash(m)&lt;/sup&gt; * g&lt;sup&gt;-r * a&lt;/sup&gt; * g&lt;sup&gt;∓r * 2&lt;sup&gt;i&lt;/sup&gt;&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p&gt;Notice that g&lt;sup&gt;-r * a&lt;/sup&gt; = (g&lt;sup&gt;a&lt;/sup&gt;)&lt;sup&gt;-r&lt;/sup&gt; = y&lt;sup&gt;-r&lt;/sup&gt;.&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;r&lt;sup&gt;s’&lt;/sup&gt; = g&lt;sup&gt;hash(m)&lt;/sup&gt; * y&lt;sup&gt;-r&lt;/sup&gt; * g&lt;sup&gt;∓r * 2&lt;sup&gt;i&lt;/sup&gt;&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p&gt;Now you can solve for g&lt;sup&gt;∓r * 2&lt;sup&gt;i&lt;/sup&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;g&lt;sup&gt;∓r * 2&lt;sup&gt;i&lt;/sup&gt;&lt;/sup&gt; = r&lt;sup&gt;s’&lt;/sup&gt; / g&lt;sup&gt;hash(m)&lt;/sup&gt; / y&lt;sup&gt;-r&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p&gt;OK, so you need to know i and whether it’s minus or plus.
But you still have to solve the DLP.
Or do you?
Remember, i is between 0 an the bit length of the secret key so you can just try them all.
Once you have e.g. +2&lt;sup&gt;5&lt;/sup&gt;, you know that the fifth bit changed from 1 to 0.&lt;/p&gt;

&lt;p&gt;You need to repeat this many times to recover most bit of the secret key.
(Actually way more than the paper estimates, since rowhammer changes the same cell with high probability.)
This is easy if the program is structured in such a way that you can start the attack with a fresh copy of the private key and corrupt just one bit.
The attack still works if you keep flipping more and more bits in the already corrupted key.
To understand this, let’s see how flipping the j-th bit would affect the above calculation.
The more corrupt private key is&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;a’’ = a ± 2&lt;sup&gt;i&lt;/sup&gt; ± 2&lt;sup&gt;j&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The two ± signs can be the same or opposite, it doesn’t matter.
You can do the above calculation again with one extra term if you want, I typed enough sup tags for today.
The final equation solved for g&lt;sup&gt;∓r * 2&lt;sup&gt;j&lt;/sup&gt;&lt;/sup&gt; will be:&lt;/p&gt;

&lt;p style=&quot;font-size:125%; text-align:center;&quot;&gt;g&lt;sup&gt;∓r * 2&lt;sup&gt;j&lt;/sup&gt;&lt;/sup&gt; = r&lt;sup&gt;s’’&lt;/sup&gt; / g&lt;sup&gt;hash(m)&lt;/sup&gt; / y&lt;sup&gt;-r&lt;/sup&gt; / g&lt;sup&gt;∓r * 2&lt;sup&gt;i&lt;/sup&gt;&lt;/sup&gt; mod (p - 1)&lt;/p&gt;

&lt;p&gt;You already know i and one of the signs from the previous step, so you can try all the j values with both plus and minus again.
Even if you don’t know i, it’s still brute forceable which might be useful if you accidentally corrupt two bits at once.&lt;/p&gt;

&lt;h1 id=&quot;rowhammer&quot;&gt;Rowhammer&lt;/h1&gt;

&lt;p&gt;The basic idea behind Rowhammer is that you can access certain DRAM cells repeatedly and sometimes the charge will leak into a nearby DRAM cell.
Cells on a DRAM chip are organized into rows, discharging and recharging (hammering) both neighbours of the target row will likely change the memory stored in that row, hence the name.
The neat or scary thing about this is the fact that it works regardless of any software or hardware access control.&lt;/p&gt;

&lt;p&gt;To target anything, you need to know the memory layout of the process (/proc/$pid/maps) and how the virtual memory is mapped to physical memory (/proc/$pid/pagemaps).
Grsecurity protects both of these but there could be other, unexpected ways I’m not thinking of.
Obviously these mappings have to be randomized for hiding them to be meaningful, which /proc/$pid/maps is, /proc/$pid/pagemaps I don’t think so.&lt;/p&gt;

&lt;p&gt;The attack doesn’t work on all RAM modules.
It doesn’t work on ECC RAM but that’s extremely expensive.
There’s a &lt;a href=&quot;https://github.com/CMU-SAFARI/rowhammer&quot;&gt;memtest fork&lt;/a&gt; that can test your hardware and a &lt;a href=&quot;https://github.com/google/rowhammer-test&quot;&gt;userspace testing utility&lt;/a&gt; that works as any user.&lt;/p&gt;

</description>
        <pubDate>Thu, 12 Mar 2015 00:00:00 +0000</pubDate>
        <link>https://blog.stribik.technology/2015/03/12/rowhammering-elgamal.html</link>
        <guid isPermaLink="true">https://blog.stribik.technology/2015/03/12/rowhammering-elgamal.html</guid>
        
        <category>crypto</category>
        
        <category>elgamal</category>
        
        <category>rowhammer</category>
        
        <category>security</category>
        
        
      </item>
    
      <item>
        <title>Secure Secure Shell</title>
        <description>&lt;p&gt;You may have heard that the NSA can decrypt SSH at least some of the time.
If you have not, then read the &lt;a href=&quot;https://www.spiegel.de/international/germany/inside-the-nsa-s-war-on-internet-security-a-1010361.html&quot;&gt;latest batch of Snowden documents&lt;/a&gt; now.
All of it.
This post will still be here when you finish.
My goal with this post here is to make NSA analysts sad.&lt;/p&gt;

&lt;p&gt;TL;DR: Scan this post for fixed width fonts, these will be the config file snippets and commands you have to use.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Warning&lt;/em&gt;: You will need a recent OpenSSH version.
It should work with 6.5 but I have only tested 6.7 and connections to Github.
Here is a good &lt;a href=&quot;http://ssh-comparison.quendi.de/comparison.html&quot;&gt;compatibility matrix&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;the-crypto&quot;&gt;The crypto&lt;/h1&gt;

&lt;p&gt;Reading the documents, I have the feeling that the NSA can 1) decrypt weak crypto and 2) steal keys.
Let’s focus on the crypto first.
SSH supports different key exchange algorithms, ciphers and message authentication codes.
The server and the client choose a set of algorithms supported by both, then proceed with the key exchange.
Some of the supported algorithms are not so great and should be disabled completely.
This hurts interoperability but everyone uses OpenSSH anyway.
Fortunately, downgrade attacks are not possible because the supported algorithm lists are included in the key derivation.
If a man in the middle were to change the lists, then the server and the client would calculate different keys.&lt;/p&gt;

&lt;h2 id=&quot;key-exchange&quot;&gt;Key exchange&lt;/h2&gt;

&lt;p&gt;There are basically two ways to do key exchange: &lt;a href=&quot;https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange&quot;&gt;Diffie-Hellman&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman&quot;&gt;Elliptic Curve Diffie-Hellman&lt;/a&gt;.
Both provide &lt;a href=&quot;https://en.wikipedia.org/wiki/Forward_secrecy&quot;&gt;forward secrecy&lt;/a&gt; which the NSA hates because they can’t use passive collection and key recovery later.
The server and the client will end up with a shared secret number at the end without a passive eavesdropper learning anything about this number.
After we have a shared secret we have to derive a cryptographic key from this using a key derivation function.
In case of SSH, this is a hash function.
&lt;a href=&quot;https://www.mitls.org/downloads/transcript-collisions.pdf&quot;&gt;Collision attacks&lt;/a&gt; on this hash function have been proven to allow downgrade attacks.&lt;/p&gt;

&lt;p&gt;DH works with a multiplicative group of integers modulo a prime.
Its security is based on the hardness of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Discrete_logarithm_problem&quot;&gt;discrete logarithm problem&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;diffie-hellman&quot;&gt;Alice           Bob
---------------------------
Sa = random
Pa = g^Sa   --&amp;gt; Pa
                Sb = random
Pb          &amp;lt;-- Pb = g^Sb
s = Pb^Sa       s = Pa^Sb
k = KDF(s)      k = KDF(s)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;ECDH works with elliptic curves over finite fields.
Its security is based on the hardness of the elliptic curve discrete logarithm problem.&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;elliptic-curve-diffie-hellman&quot;&gt;Alice           Bob
---------------------------
Sa = random
Pa = Sa * G --&amp;gt; Pa
                Sb = random
Pb          &amp;lt;-- Pb = Sb * G
s = Sa * Pb     s = Sb * Pa
k = KDF(s)      k = KDF(s)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OpenSSH supports 11 key exchange protocols:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt&quot;&gt;curve25519-sha256&lt;/a&gt;: ECDH over &lt;a href=&quot;https://cr.yp.to/ecdh.html&quot;&gt;Curve25519&lt;/a&gt; with SHA2&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ietf.org/rfc/rfc4253.txt&quot;&gt;diffie-hellman-group1-sha1&lt;/a&gt;: 1024 bit DH with SHA1&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ietf.org/rfc/rfc4253.txt&quot;&gt;diffie-hellman-group14-sha1&lt;/a&gt;: 2048 bit DH with SHA1&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-curdle-ssh-modp-dh-sha2-09&quot;&gt;diffie-hellman-group14-sha256&lt;/a&gt;: 2048 bit DH with SHA2&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-curdle-ssh-modp-dh-sha2-09&quot;&gt;diffie-hellman-group16-sha512&lt;/a&gt;: 4096 bit DH with SHA2&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-curdle-ssh-modp-dh-sha2-09&quot;&gt;diffie-hellman-group18-sha512&lt;/a&gt;: 8192 bit DH with SHA2&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ietf.org/rfc/rfc4419.txt&quot;&gt;diffie-hellman-group-exchange-sha1&lt;/a&gt;: Custom DH with SHA1&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ietf.org/rfc/rfc4419.txt&quot;&gt;diffie-hellman-group-exchange-sha256&lt;/a&gt;: Custom DH with SHA2&lt;/li&gt;
  &lt;li&gt;ecdh-sha2-nistp256: ECDH over NIST P-256 with SHA2&lt;/li&gt;
  &lt;li&gt;ecdh-sha2-nistp384: ECDH over NIST P-384 with SHA2&lt;/li&gt;
  &lt;li&gt;ecdh-sha2-nistp521: ECDH over NIST P-521 with SHA2&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We have to look at 3 things here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;ECDH curve choice&lt;/em&gt;:
This eliminates 9-11 because &lt;a href=&quot;https://blog.cr.yp.to/20140323-ecdsa.html&quot;&gt;NIST curves suck&lt;/a&gt;.
They leak secrets through timing side channels and off-curve inputs.
Also, &lt;a href=&quot;https://projectbullrun.org/dual-ec/vulnerability.html&quot;&gt;NIST is considered harmful&lt;/a&gt; and cannot be trusted.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Bit size of the DH modulus&lt;/em&gt;:
This eliminates 2 because the NSA has supercomputers and possibly unknown attacks.
1024 bits simply don’t offer sufficient security margin.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Security of the hash function&lt;/em&gt;:
This eliminates 2, 3, and 7 because SHA1 is broken.
We don’t have to wait for a second preimage attack that takes 10 minutes on a cellphone to disable it right now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are left with 1 and 8, as well as 4-6 which were added in &lt;a href=&quot;https://www.openssh.com/releasenotes.html#7.3&quot;&gt;OpenSSH 7.3&lt;/a&gt;.
1 is better and it’s perfectly OK to only support that but for interoperability (with Eclipse, WinSCP), 8 can be included.&lt;/p&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-kex&quot;&gt;KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/ssh_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;client-kex&quot;&gt;# Github needs diffie-hellman-group-exchange-sha1 some of the time but not always.
#Host github.com
#    KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1
    
Host *
    KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you chose to enable 8, open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/moduli&lt;/code&gt; if exists, and delete lines where the 5th column is less than 2000.&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-moduli-filter&quot;&gt;awk '$5 &amp;gt; 2000' /etc/ssh/moduli &amp;gt; &quot;${HOME}/moduli&quot;
wc -l &quot;${HOME}/moduli&quot; # make sure there is something left
mv &quot;${HOME}/moduli&quot; /etc/ssh/moduli&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If it does not exist, create it:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-moduli&quot;&gt;ssh-keygen -G /etc/ssh/moduli.all -b 4096
ssh-keygen -T /etc/ssh/moduli.safe -f /etc/ssh/moduli.all
mv /etc/ssh/moduli.safe /etc/ssh/moduli
rm /etc/ssh/moduli.all&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will take a while so continue while it’s running.&lt;/p&gt;

&lt;h2 id=&quot;authentication&quot;&gt;Authentication&lt;/h2&gt;

&lt;p&gt;The key exchange ensures that the server and the client shares a secret no one else knows.
We also have to make sure that they share this secret with each other and not an NSA analyst.&lt;/p&gt;

&lt;h3 id=&quot;server-authentication&quot;&gt;Server authentication&lt;/h3&gt;

&lt;p&gt;The server proves its identity to the client by signing the key resulting from the key exchange.
There are 4 public key algorithms for authentication:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;DSA with SHA1&lt;/li&gt;
  &lt;li&gt;ECDSA with SHA256, SHA384 or SHA512 depending on key size&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ed25519.cr.yp.to/&quot;&gt;Ed25519&lt;/a&gt; with SHA512&lt;/li&gt;
  &lt;li&gt;RSA with SHA1&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;DSA keys must be exactly 1024 bits so let’s disable that.
Number 2 here involves NIST suckage and should be disabled as well.
Another important disadvantage of DSA and ECDSA is that it uses randomness for each signature.
If the random numbers are not the best quality, then it is &lt;a href=&quot;https://security.stackexchange.com/a/46781&quot;&gt;possible to recover&lt;/a&gt; the &lt;a href=&quot;https://events.ccc.de/congress/2010/Fahrplan/attachments/1780%5F27c3%5Fconsole%5Fhacking%5F2010.pdf&quot;&gt;secret key&lt;/a&gt;.
Fortunately, RSA using SHA1 is not a problem here because the value being signed is actually a SHA2 hash.
The hash function SHA1(SHA2(x)) is just as secure as SHA2 (it has less bits of course but no better attacks).&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-auth&quot;&gt;Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first time you connect to your server, you will be asked to accept the new fingerprint.&lt;/p&gt;

&lt;p&gt;This will also disable the horribly broken v1 protocol that you should not have enabled in the first place.
We should remove the unused keys and only generate a large RSA key and an Ed25519 key.
Your init scripts may recreate the unused keys.
If you don’t want that, remove any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh-keygen&lt;/code&gt; commands from the init script.&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-keygen&quot;&gt;cd /etc/ssh
rm ssh_host_*key*
ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N &quot;&quot; &amp;lt; /dev/null
ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key -N &quot;&quot; &amp;lt; /dev/null&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;client-authentication&quot;&gt;Client authentication&lt;/h3&gt;

&lt;p&gt;The client must prove its identity to the server as well.
There are various methods to do that.&lt;/p&gt;

&lt;p&gt;The simplest is password authentication.
This should be disabled immediately &lt;em&gt;after&lt;/em&gt; setting up a more secure method because it allows compromised servers to steal passwords.
Password authentication is also more vulnerable to online bruteforce attacks.&lt;/p&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-auth-password&quot;&gt;PasswordAuthentication no
ChallengeResponseAuthentication no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/ssh_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;client-auth-password&quot;&gt;Host *
    PasswordAuthentication no
    ChallengeResponseAuthentication no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The most common and secure method is public key authentication, basically the same process as the server authentication.&lt;/p&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-auth-pubkey&quot;&gt;PubkeyAuthentication yes&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/ssh_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;client-auth-pubkey&quot;&gt;Host *
    PubkeyAuthentication yes
    HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Generate client keys using the following commands:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;client-keygen&quot;&gt;ssh-keygen -t ed25519 -o -a 100
ssh-keygen -t rsa -b 4096 -o -a 100&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can deploy your new client public keys using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh-copy-id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is also possible to use OTP authentication to reduce the consequences of lost passwords.
&lt;a href=&quot;https://github.com/google/google-authenticator/wiki/PAM-Module-Instructions&quot;&gt;Google Authenticator&lt;/a&gt; is a nice implementation of &lt;a href=&quot;https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm&quot;&gt;TOTP&lt;/a&gt;, or Timebased One Time Password.
You can also use a &lt;a href=&quot;https://www.cl.cam.ac.uk/~mgk25/otpw.html&quot;&gt;printed list of one time passwords&lt;/a&gt; or any other &lt;a href=&quot;https://en.wikipedia.org/wiki/Pluggable_authentication_module&quot;&gt;PAM&lt;/a&gt; module, really, if you enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ChallengeResponseAuthentication&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;user-authentication&quot;&gt;User Authentication&lt;/h3&gt;

&lt;p&gt;Even with Public Key authentication, you should only allow incoming connections from expected users.  The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AllowUsers&lt;/code&gt; setting in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshd_config&lt;/code&gt; lets you specify users who are allowed to connect, but this can get complicated with a large number of ssh users.  Additionally, when deleting a user from the system, the username is &lt;a href=&quot;https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779880&quot;&gt;not removed&lt;/a&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshd_config&lt;/code&gt;, which adds to maintenance requirements.  The solution is to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AllowGroups&lt;/code&gt; setting instead, and add users to an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh-user&lt;/code&gt; group.&lt;/p&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;client-auth-allowgroups&quot;&gt;AllowGroups ssh-user&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create the ssh-user group with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo groupadd ssh-user&lt;/code&gt;, then add each ssh user to the group with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo usermod -a -G ssh-user &amp;lt;username&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;symmetric-ciphers&quot;&gt;Symmetric ciphers&lt;/h2&gt;

&lt;p&gt;Symmetric ciphers are used to encrypt the data after the initial key exchange and authentication is complete.&lt;/p&gt;

&lt;p&gt;Here we have quite a few algorithms (10-14 were removed in &lt;a href=&quot;https://www.openssh.com/releasenotes.html#7.6&quot;&gt;OpenSSH 7.6&lt;/a&gt;):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;3des-cbc&lt;/li&gt;
  &lt;li&gt;aes128-cbc&lt;/li&gt;
  &lt;li&gt;aes192-cbc&lt;/li&gt;
  &lt;li&gt;aes256-cbc&lt;/li&gt;
  &lt;li&gt;aes128-ctr&lt;/li&gt;
  &lt;li&gt;aes192-ctr&lt;/li&gt;
  &lt;li&gt;aes256-ctr&lt;/li&gt;
  &lt;li&gt;aes128-gcm@openssh.com&lt;/li&gt;
  &lt;li&gt;aes256-gcm@openssh.com&lt;/li&gt;
  &lt;li&gt;arcfour&lt;/li&gt;
  &lt;li&gt;arcfour128&lt;/li&gt;
  &lt;li&gt;arcfour256&lt;/li&gt;
  &lt;li&gt;blowfish-cbc&lt;/li&gt;
  &lt;li&gt;cast128-cbc&lt;/li&gt;
  &lt;li&gt;chacha20-poly1305@openssh.com&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We have to consider the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Security of the cipher algorithm&lt;/em&gt;:
This eliminates 1 and 10-12 - both DES and RC4 are broken.
Again, no need to wait for them to become even weaker, disable them now.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Key size&lt;/em&gt;:
At least 128 bits, the more the better.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Block size&lt;/em&gt;:
Does not apply to stream ciphers.
At least 128 bits.
This eliminates 13 and 14 because those have a 64 bit block size.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Cipher mode&lt;/em&gt;:
The recommended approach here is to prefer &lt;a href=&quot;https://en.wikipedia.org/wiki/Authenticated_encryption&quot;&gt;AE&lt;/a&gt; modes and optionally allow CTR for compatibility.
CTR with Encrypt-then-MAC is provably secure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chacha20-poly1305 is preferred over AES-GCM because the SSH protocol &lt;a href=&quot;http://blog.djm.net.au/2013/11/chacha20-and-poly1305-in-openssh.html&quot;&gt;does not encrypt message sizes&lt;/a&gt; when GCM (or EtM) is in use.
This allows some traffic analysis even without decrypting the data.
We will deal with that soon.&lt;/p&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-ciphers&quot;&gt;Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/ssh_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;client-ciphers&quot;&gt;Host *
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;message-authentication-codes&quot;&gt;Message authentication codes&lt;/h2&gt;

&lt;p&gt;Encryption provides &lt;em&gt;confidentiality&lt;/em&gt;, message authentication code provides &lt;em&gt;integrity&lt;/em&gt;.
We need both.
If an AE cipher mode is selected, then extra MACs are not used, the integrity is already given.
If CTR is selected, then we need a MAC to calculate and attach a tag to every message.&lt;/p&gt;

&lt;p&gt;There are multiple ways to combine ciphers and MACs - not all of these are useful.
The 3 most common:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Encrypt-then-MAC&lt;/em&gt;: encrypt the message, then attach the MAC of the ciphertext.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;MAC-then-encrypt&lt;/em&gt;: attach the MAC of the plaintext, then encrypt everything.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Encrypt-and-MAC&lt;/em&gt;: encrypt the message, then attach the MAC of the plaintext.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only Encrypt-then-MAC should be used, period.
Using MAC-then-encrypt have lead to many attacks on TLS while Encrypt-and-MAC have lead to not quite that many attacks on SSH.
The reason for this is that the more you fiddle with an attacker provided message, the more chance the attacker has to gain information through side channels.
In case of Encrypt-then-MAC, the MAC is verified and if incorrect, discarded.
Boom, one step, no timing channels.
In case of MAC-then-encrypt, first the attacker provided message has to be decrypted and only then can you verify it.
Decryption failure (due to invalid CBC padding for example) may take less time than verification failure.
Encrypt-and-MAC also has to be decrypted first, leading to the same kind of potential side channels.
It’s even worse because no one said that a MAC’s output can’t leak what its input was.
SSH by default, uses this method.&lt;/p&gt;

&lt;p&gt;Here are the available MAC choices:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;hmac-md5&lt;/li&gt;
  &lt;li&gt;hmac-md5-96&lt;/li&gt;
  &lt;li&gt;hmac-sha1&lt;/li&gt;
  &lt;li&gt;hmac-sha1-96&lt;/li&gt;
  &lt;li&gt;hmac-sha2-256&lt;/li&gt;
  &lt;li&gt;hmac-sha2-512&lt;/li&gt;
  &lt;li&gt;umac-64&lt;/li&gt;
  &lt;li&gt;umac-128&lt;/li&gt;
  &lt;li&gt;hmac-md5-etm@openssh.com&lt;/li&gt;
  &lt;li&gt;hmac-md5-96-etm@openssh.com&lt;/li&gt;
  &lt;li&gt;hmac-sha1-etm@openssh.com&lt;/li&gt;
  &lt;li&gt;hmac-sha1-96-etm@openssh.com&lt;/li&gt;
  &lt;li&gt;hmac-sha2-256-etm@openssh.com&lt;/li&gt;
  &lt;li&gt;hmac-sha2-512-etm@openssh.com&lt;/li&gt;
  &lt;li&gt;umac-64-etm@openssh.com&lt;/li&gt;
  &lt;li&gt;umac-128-etm@openssh.com&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The selection considerations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Security of the hash algorithm&lt;/em&gt;:
No MD5 and SHA1.
Yes, I know that HMAC-SHA1 does not need collision resistance but why wait?
Disable weak crypto today.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Encrypt-then-MAC&lt;/em&gt;:
I am not aware of a security proof for CTR-and-HMAC but I also don’t think CTR decryption can fail.
Since there are no downgrade attacks, you can add them to the end of the list.
You can also do this on a host by host basis so you know which ones are less safe.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Tag size&lt;/em&gt;:
At least 128 bits.
This eliminates umac-64-etm.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Key size&lt;/em&gt;:
At least 128 bits.
This doesn’t eliminate anything at this point.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;server-macs&quot;&gt;MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/ssh_config&lt;/code&gt; snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;client-macs&quot;&gt;Host *
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&quot;preventing-key-theft&quot;&gt;Preventing key theft&lt;/h1&gt;

&lt;p&gt;Even with forward secrecy the secret keys must be kept secret.
The NSA has a database of stolen keys - you do not want your key there.&lt;/p&gt;

&lt;h2 id=&quot;system-hardening&quot;&gt;System hardening&lt;/h2&gt;

&lt;p&gt;OpenSSH has some undocumented, and rarely used features.
UseRoaming is one such feature with a &lt;a href=&quot;https://security.stackexchange.com/questions/110639/how-exploitable-is-the-recent-useroaming-ssh-problem&quot;&gt;known vulnerability&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recommended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/ssh_config&lt;/code&gt; snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code id=&quot;client-features&quot;&gt;Host *
   UseRoaming no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This post is not intended to be a comprehensive system security guide.
Very briefly:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Don’t install what you don’t need&lt;/em&gt;:
Every single line of code has a chance of containing a bug.
Some of these bugs are security holes.
Fewer lines, fewer holes.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Use free software&lt;/em&gt;:
As in speech.
You want to use code that’s actually reviewed or that you can review yourself.
There is no way to achieve that without source code.
Someone may have reviewed proprietary crap but who knows.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Keep your software up to date&lt;/em&gt;:
New versions often fix critical security holes.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Exploit mitigation&lt;/em&gt;:
Sad but true - there will always be security holes in your software.
There are things you can do to prevent their exploitation, such as GCC’s -fstack-protector.
One of the best security projects out there is &lt;a href=&quot;https://grsecurity.net/&quot;&gt;Grsecurity&lt;/a&gt;.
Use it or use OpenBSD.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;traffic-analysis-resistance&quot;&gt;Traffic analysis resistance&lt;/h2&gt;

&lt;p&gt;Set up &lt;a href=&quot;https://www.torproject.org/docs/hidden-services.html.en&quot;&gt;Tor hidden services&lt;/a&gt; for your SSH servers.
This has multiple advantages.
It provides an additional layer of encryption and server authentication.
People looking at your traffic will not know your IP, so they will be unable to scan and target other services running on the same server and client.
Attackers can still attack these services but don’t know if it has anything to do with the observed traffic until they actually break in.&lt;/p&gt;

&lt;p&gt;Now this is only true if you don’t disclose your SSH server’s fingerprint in any other way.
You should only accept connections from the hidden service or from LAN, if required.&lt;/p&gt;

&lt;p&gt;If you don’t need LAN access, you can add the following line to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;localhost-only&quot;&gt;ListenAddress 127.0.0.1:22&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add this to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/tor/torrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;hidden-service&quot;&gt;HiddenServiceDir /var/lib/tor/hidden_service/ssh
HiddenServicePort 22 127.0.0.1:22&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You will find the hostname you have to use in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/lib/tor/hidden_service/ssh/hostname&lt;/code&gt;.
You also have to configure the client to use Tor.
For this, socat will be needed.
Add the following line to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/ssh_config&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code id=&quot;onion-proxy&quot;&gt;Host *.onion
    ProxyCommand socat - SOCKS4A:localhost:%h:%p,socksport=9050

Host *
    ...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to allow connections from LAN, don’t use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListenAddress&lt;/code&gt; line, configure your firewall instead.&lt;/p&gt;

&lt;h2 id=&quot;key-storage&quot;&gt;Key storage&lt;/h2&gt;

&lt;p&gt;You should encrypt your client key files using a strong password.
Additionally, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh-keygen -o -a $number&lt;/code&gt; to slow down cracking attempts by iterating the hash function many times.
You may want to store them on a pendrive and only plug it in when you want to use SSH.
Are you more likely to lose your pendrive or have your system compromised?
I don’t know.&lt;/p&gt;

&lt;p&gt;Unfortunately, you can’t encrypt your server key and it must be always available, or else sshd won’t start.
The only thing protecting it is OS access controls.&lt;/p&gt;

&lt;h1 id=&quot;the-end&quot;&gt;The end&lt;/h1&gt;

&lt;p&gt;It’s probably a good idea to test the changes.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh -v&lt;/code&gt; will print the selected algorithms and also makes problems easier to spot.
Be extremely careful when configuring SSH on a remote host.
Always keep an active session, never restart sshd.
Instead you can send the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGHUP&lt;/code&gt; signal to reload the configuration without killing your session.
You can be even more careful by starting a new sshd instance on a different port and testing that.&lt;/p&gt;

&lt;p&gt;Can you make these changes?
If the answer is yes, then…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/nsa-happy-dance.png&quot; alt=&quot;NSA Happy Dance&quot; title=&quot;Happy Dance!!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If the answer is no, it’s probably due to compatibility problems.
You can try to convince the other side to upgrade their security and turn it into a yes.
I have created a &lt;a href=&quot;https://github.com/stribika/stribika.github.io/wiki/Secure-Secure-Shell&quot;&gt;wiki page&lt;/a&gt; where anyone can add config files for preserving compatibility with various SSH implementations and SSH based services.&lt;/p&gt;

&lt;p&gt;If you work for a big company and change management doesn’t let you do it, I’m sorry.
I’ve seen the v1 protocol enabled in such places.
There is no chance of improvement.
Give up to preseve your sanity.&lt;/p&gt;

&lt;p&gt;Special thanks to the people of Twitter for the improvements.&lt;/p&gt;

&lt;h1 id=&quot;changelog&quot;&gt;ChangeLog&lt;/h1&gt;

&lt;p&gt;You may have noticed that this document changed since last time.
I want to be very transparent about this.
There were three major changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;After some debate and going back and forth between including GCM or not, it’s now back again.
The reason for dropping it was that SSH doesn’t encrypt packet sizes when using GCM.
The reason for bringing it back is that SSH does the same with any EtM algorithms.
There is no way around this unless you can live with chacha20-poly1305 only.
Also, the leaked documents don’t sound like they can figure out the lengths or confirm presence of some things, more like straight up “send it to us and we’ll decrypt it for you”.
Wrapping SSH in a Tor hidden service will take care of any traffic analysis concerns.&lt;/li&gt;
  &lt;li&gt;I’m now allowing Encrypt-and-MAC algorithms with CTR ciphers as a last resort.
I initially thought it was possible to use downgrade attacks, I now think it is not.&lt;/li&gt;
  &lt;li&gt;I briefly disabled RSA because it uses SHA1, this turned out to be a non-issue because we’re signing SHA2 hashes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see the &lt;a href=&quot;https://github.com/stribika/stribika.github.io/commits/master/_posts/2015-01-04-secure-secure-shell.md&quot;&gt;full list of changes&lt;/a&gt; on github.
I promise not to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push -f&lt;/code&gt;.&lt;/p&gt;

</description>
        <pubDate>Sun, 04 Jan 2015 00:00:00 +0000</pubDate>
        <link>https://blog.stribik.technology/2015/01/04/secure-secure-shell.html</link>
        <guid isPermaLink="true">https://blog.stribik.technology/2015/01/04/secure-secure-shell.html</guid>
        
        <category>crypto</category>
        
        <category>nsa</category>
        
        <category>ssh</category>
        
        
      </item>
    
      <item>
        <title>What have I done</title>
        <description>&lt;p&gt;I did something no one should ever do: I invented my own key derivation function, &lt;a href=&quot;https://github.com/stribika/bfkdf&quot;&gt;BFKDF&lt;/a&gt;.
It’s based on &lt;a href=&quot;https://www.tarsnap.com/scrypt.html&quot;&gt;scrypt&lt;/a&gt; so it can’t be too bad.
I tried to make sure it’s &lt;em&gt;not worse&lt;/em&gt; than scrypt.
There is also some &lt;a href=&quot;https://en.wikipedia.org/wiki/Brainfuck&quot;&gt;brainfuck&lt;/a&gt; involved which might just make me the only person who ever unironically used the language.&lt;/p&gt;

&lt;p&gt;Why would I do something like that?
Well, it all started with a new Twitter &lt;a href=&quot;https://samaritansradar.org&quot;&gt;app&lt;/a&gt; which scrapes the website, stores all the tweets, greps for suicidal thoughts and sends alerts to friends.
Sounds like a good idea, excepts it’s really not and it raises privacy concerns.
True, Twitter is a public website.
Unless you have a private account every tweet you ever sent is preserved forever and publicly available.
However, there is a slight difference between just having it out there and having it analyzed, flagged, and e-mailed out to people.
Insurance companies could refuse contracts or ask for higher fees if they know you are a “riskier” customer.&lt;/p&gt;

&lt;p&gt;Naturally, whenever Twitter does something stupid, the topic of writing a distributed replacement comes up.
But how would we do better?
We’d like to keep it public, that’s the best part of Twitter, but we don’t want to allow anyone to collect all tweets.
The only difference between a normal user and a scraper is the number of followed users and, in turn, the number of tweets read per second.
We could encrypt them with a mostly zero key and tune it so cracking one takes about a second on a cellphone.
Not a problem for regular users but it at least makes cracking all of them a little more difficult.
We can make it more difficult by using a key derivation function such as &lt;a href=&quot;https://en.wikipedia.org/wiki/PBKDF2&quot;&gt;PBKDF2&lt;/a&gt; or scrypt as &lt;code&gt;encrypt(kdf(mostly_zeros), message)&lt;/code&gt;.
The problem is that a cracking farm can beat a billion cellphones with specialized hardware.
The great thing about scrypt is that it adds a large memory requirement for parallel cracking but cellphones have some RAM anyway and they don’t have to crack in parallel.
There are only a few tweets coming in every few seconds.
Cellphones also have a CPU.
If you ever tried to mine bitcoins you know that this is something you want to avoid in a cracking circuit.
You want as many copies of a pipelined implementation as you can fit on a chip.&lt;/p&gt;

&lt;p&gt;My idea was to force them to include a fully functional CPU by generating deterministic random Turing complete code, give it deterministic random input and include the output in the final hash.
Brainfuck happens to be pretty easy to randomly generate.
We can’t just generate any sequence of the 8 opcodes but almost.
A brainfuck program is only valid if it contains an equal number of “[” and “]” characters and, counting from left to right, there are never more “]”s than “[”s.
Let’s try to count how many n character programs there are and the way to generate them with equal probability will follow.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The number of 0 character programs is 1.
It’s just the empty string.&lt;/li&gt;
  &lt;li&gt;The number of 1 character programs is 6 because it can’t be any of the brackets.&lt;/li&gt;
  &lt;li&gt;The number of n &amp;gt; 1 character programs can be expressed recursively.
    &lt;ul&gt;
      &lt;li&gt;If the first character is not a bracket, then there are &lt;code&gt;6 * f(n - 1)&lt;/code&gt; possible programs.&lt;/li&gt;
      &lt;li&gt;If the first character is “[”, then we have to choose where to put the matching “]”.
        &lt;ul&gt;
          &lt;li&gt;Let &lt;code&gt;0 &amp;lt; k &amp;lt; n&lt;/code&gt; be this position.&lt;/li&gt;
          &lt;li&gt;For each possible k, there are &lt;code&gt;f(k - 1) * f(n - k - 1)&lt;/code&gt; possible programs.&lt;/li&gt;
          &lt;li&gt;Using python notation, that’s &lt;code&gt;sum([ f(k-1) * f(n-k-1) for k in range(1, n) ])&lt;/code&gt;.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;The first character can’t be “]”.&lt;/li&gt;
      &lt;li&gt;That’s &lt;code&gt;6 * f(n - 1) + sum([ f(k - 1) * f(n - k - 1) for k in range(1, n) ])&lt;/code&gt;.
Cool.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s easy to see that this is between 6^n and 7^n but I can’t be arsed to give you an exact number.
It’s not important, there are enough.
By following the above description and choosing the first character randomly from the 7 possible, then choosing k from uniformly if needed, then repeat recursively, we will pick each program with the same probability.&lt;/p&gt;

&lt;p&gt;Now, there are &lt;em&gt;few things&lt;/em&gt; we have to pay attention to when writing cryptographic code.
One of the most important things is making sure the runtime of the algorithm does not depend on secret values.
If we would seed a regular random number generator directly with the input of our brand new KDF and use it to generate brainfuck and its input, then measuring the runtime would probably tell the attacker everything they need to break it.
It would still be OK for the Distributed Twitter scenario but not much else.
Instead, let’s scrypt the input, use that as a key and IV for &lt;a href=&quot;https://en.wikipedia.org/wiki/Advanced_Encryption_Standard&quot;&gt;AES&lt;/a&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29&quot;&gt;CTR&lt;/a&gt;, then take the bitstream and use that.&lt;/p&gt;

&lt;p&gt;The next problem is the quality of random numbers generated by brainfuck.
It sucks.
It’s true, all programs have the same probability but many of them are equivalent.
Infinite loops without output are common and so are infinite loops that output a short repeating sequence.
Brainfuck control flow only distinguishes zeros and non-zeros, therefore the output contains too many 00, 01 and ff bytes.
We can repeat this process until the output matches some complicated randomness condition but it will still suck.
So let’s scrypt the output again, that’s what it’s good at, it makes shitty passwords secure.
Finally, we append the input to this and scrypt the whole thing again.&lt;/p&gt;

</description>
        <pubDate>Fri, 14 Nov 2014 00:00:00 +0000</pubDate>
        <link>https://blog.stribik.technology/2014/11/14/what-have-i-done.html</link>
        <guid isPermaLink="true">https://blog.stribik.technology/2014/11/14/what-have-i-done.html</guid>
        
        <category>brainfuck</category>
        
        <category>crypto</category>
        
        <category>python</category>
        
        
      </item>
    
  </channel>
</rss>
