David Wong | Cryptologie | HTML http://www.cryptologie.net/ About my studies in Cryptography. en-us Mon, 22 Jan 2018 12:12:13 +0100 Two Student Tickets for Black Hat Asia in March 2018 David Wong Mon, 22 Jan 2018 12:12:13 +0100 http://www.cryptologie.net/article/438/two-student-tickets-for-black-hat-asia-in-march-2018/ http://www.cryptologie.net/article/438/two-student-tickets-for-black-hat-asia-in-march-2018/#comments I'll be giving a talk at Black Hat Asia with Mason in a few months, and thus I was given two tickets for students to come attend the conference for free.

Anyone interested?

On Real World Crypto and Secure Messaging David Wong Thu, 11 Jan 2018 00:49:42 +0100 http://www.cryptologie.net/article/437/on-real-world-crypto-and-secure-messaging/ http://www.cryptologie.net/article/437/on-real-world-crypto-and-secure-messaging/#comments Paul Rösler and Christian Mainka and Jörg Schwenk released More is Less: On the End-to-End Security of Group Chats in Signal, WhatsApp, and Threema in July 2017.

Today Paul Rösler came to Real World Crypto to talk about the results, which is a good thing. Interestingly, in the middle of the talk Wired released a worrying article untitled WhatsApp Security Flaws Could Allow Snoops to Slide Into Group Chats.
Interestingly as well, at some point during the day Matthew Green also wrote about it in Attack of the Week: Group Messaging in WhatsApp and Signal.

They make it seem really worrisome, but should we really be scared about the findings?

Traceable delivery is the first thing that came up in the presentation. What is it? It’s the check marks that appear when your recipient receives a message you sent. It's mostly a UI feature but the fact that no security is tied to it allows a server to fake them while dropping messages, making you think that your recipient has wrongly received the message. This was never a security feature to begin with, and nobody never claimed it was one.

Closeness is the fact that the WhatsApp servers can add a new participant into your private group chat without your consent (assuming you’re the admin). This could lead people to share messages to the group including to a rogue participant. The caveat is that:

  • previous messages cannot be decrypted by the newcomer because a new key is generated when someone new joins the mix

  • everybody is receiving a notification that somebody joined, at this point everyone can choose to willingly send messages to the group

Again, I do not see this as a security vulnerability. Maybe because I’ve understood how group chats can work (or miswork) from growing up with shady websites and applications. But I see this more as a UI/UX problem.

The paper is not bad though, and I think they’re right to point out these issues. Actually, they do something very interesting in it, they start it up with a nice security model that they use to analyse several messaging applications:

Intuitively, a secure group communication protocol should provide a level of security comparable to when a group of people communicates in an isolated room: everyone in the room hears the communication (traceable delivery), everyone knows who spoke (authenticity) and how often words have been said (no duplication), nobody outside the room can either speak into the room (no creation) or hear the communication inside (confidentiality), and the door to the room is only opened for invited persons (closeness).

Following this security model, you could rightfully think that we haven’t reached the best state in secure messaging. But the fuss about it could also wrongfully make you think that these are worrisome attacks that need to be dealt with.

The facts are here though, this paper has been blown out of proportion. Moxie (one of the creator of Signal) reacts on hackernews:

To me, this article reads as a better example of the problems with the security industry and the way security research is done today, because I think the lesson to anyone watching is clear: don't build security into your products, because that makes you a target for researchers, even if you make the right decisions, and regardless of whether their research is practically important or not.

I'd say the problem is in the reaction, not in the published analysis. But it's a sad reaction indeed.

Good night.

Updates on How to Backdoor Diffie-Hellman David Wong Mon, 08 Jan 2018 18:12:54 +0100 http://www.cryptologie.net/article/436/updates-on-how-to-backdoor-diffie-hellman/ http://www.cryptologie.net/article/436/updates-on-how-to-backdoor-diffie-hellman/#comments Early in 2016, I published a whitepaper (here on eprint) on how to backdoor the Diffie-Hellman key agreement algorithm. Inside the whitepaper, I discussed three different ways to construct such a backdoor; two of these were considered nobody-but-us (NOBUS) backdoors.

A NOBUS backdoor is a backdoor accessible only to those who have the knowledge of some secret (a number, a passphrase, ...). Making a NOBUS backdoor irreversible without the knowledge of the secret.

In October 2016, Dorey et al. from Western University (Canada) published a white paper called Indiscreet Logs: Persistent Diffie-Hellman Backdoors in TLS. The research pointed out that one of my NOBUS construction was reversible, while the other NOBUS construction was more dangerous than expected.

I wrote this blogpost resuming their discoveries a long time ago, but never took the time to publish it here. In the rest of this post, I'll expect you to have an understanding of the two NOBUS backdoors introduced in my paper. You can find a summary of the ideas here as well.

Reversing the first NOBUS construction

For those who have attended my talk at Defcon, Toorcon or a meetup; I should assure you that I did not talk about the first (now-known reversible) NOBUS construction. It was left out of the story because it was not such a nice backdoor in the first place. Its security margins were weaker (at the time) compared to the second construction, and it was also harder to implement.

Baby-Step Giant-Step

The attack Dorey et al. wrote about comes from a 2005 white paper, where Coron et al. published an attack on a construction based on Diffie-Hellman. But before I can tell you about the attack, I need to refresh your memory on how the baby-step giant-step (BSGS) algorithm works.

Imagine that a generator \(g\) generates a group \(G\) in \(\mathbb{Z}_p\), and that we want to find the order of that group \(|G| = p_1\).

Now what we could do if we have a good idea of the size of that order \(p_1\), is to split that length in two right in the middle: \(p_1 = a + b \cdot 2^{\lceil \frac{l}{2} \rceil}\), where \( l \) is the bitlength of \(p_1\).

This allows us to write two different lists:

\[ \begin{cases} L = { g^i \mod{p} \mid 0 < i < 2^{\lceil \frac{l}{2} \rceil} } \\ L' = { g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil} } \mod{p} \mid 0 \leq j < 2^{\lceil \frac{l}{2} \rceil} } \end{cases} \]

Now imagine that you compute these two lists, and that you then stumble upon a collision between elements from these two sets. This would entail that for some \(i\) and \(j\) you have:

\[ \begin{align} &g^i = g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil}} \pmod{p}\\ \Leftrightarrow &g^{i + j \cdot 2^{\lceil \frac{l}{2} \rceil}} = 1 \pmod{p}\\ \Rightarrow &i + j \cdot 2^{\lceil \frac{l}{2} \rceil} = a + b \cdot 2^{\lceil \frac{l}{2} \rceil} = p_1 \end{align} \]

We found \(p_1\) in time quasi-linear (via sorting, searching trees, etc...) in \(\sqrt{p_1}\)!

The Construction

Now let's review our first NOBUS construction, detailed in section 4 of my paper.


Here \(p - 1 = 2 p_1 p_2 \) with \( p_1 \) our small-enough subgroup generated by \(g\) in \(\mathbb{Z}_p\), and \(p_2\) our big-enough subgroup that makes the factorization of our modulus near-impossible. The factor \(q\) is generated in the same way.

Using BSGS on our construction

At this point, we could try to reverse the construction using BSGS by creating these two lists and hopping for a collision:

\[ \begin{cases} L = { g^i \mod{p} \mid 0 < i < 2^{\lceil \frac{l}{2} \rceil} } \\ L' = { g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil} } \mod{p} \mid 0 \leq j < 2^{\lceil \frac{l}{2} \rceil} } \end{cases} \]

Unfortunately, remember that \(p\) is hidden inside of \( n = p q \). We have no knowledge of that factor. Instead, we could calculate these two lists:

\[ \begin{cases} L = { g^i \mod{n} \mid 0 < i < 2^{\lceil \frac{l}{2} \rceil} } \\ L' = { g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil} } \mod{n} \mid 0 \leq j < 2^{\lceil \frac{l}{2} \rceil} } \end{cases} \]

And this time, we can test for a collision between two elements of these lists "mod \(p\)" via the \(gcd\) function:

\[ gcd(n, g^i - g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil}}) \]

Hopefully this will yield \(p\), one of the factor of \(n\). If you do not understand why, it works because if \(g^i\) and \(g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil}}\) collide "mod \(p\)", then we have:

\[ p | g^i - g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil}} \]

Since we also know that \( p | n \), it results that the \(gcd\) of the two returns our hidden \(p\)!

Unfortunately at this point, the persnickety reader will have noticed that this cannot be done in the same complexity as the original BSGS attack. Indeed, we need to compute the \(gcd\) for all pairs and this increases our complexity to \(\mathcal{O}(p_1)\), the same complexity as the attack I pointed out in my paper.

The Attack

Now here is the that trick Coron et al. found out. They could optimize calls to \(gcd\) down to \(\mathcal{O}(\sqrt{p_1})\), which would make the reversing as easy as using the backdoor. The trick is as follow:

  1. Create the polynomial

\[ f(x) = (x - g) (x - g^2) \cdots (x - g^{2^{\lceil \frac{l}{2} \rceil}}) \mod{n} \]

  1. For \(0 \leq j < 2^{\lceil \frac{l}{2} \rceil}\) compute the following \(gcd\) until a factor of \(n\) is found (as before)

\[ gcd(n, f(g^{-j \cdot 2^{\lceil \frac{l}{2} \rceil}})) \]

It's pretty easy to see that the \(gcd\) will still yield a factor, as before. Except that this time we only need to call it at most \(2^{\lceil \frac{l}{2} \rceil}\) times, which is \(\approx \sqrt{p_1}\) times by definition.

Improving the second NOBUS construction

The second NOBUS backdoor construction received a different treatment. If you do not know how this backdoor works I urge you to first watch my talk on the subject.

Let's ask ourselves the question: what happens if the client and the server do not negotiate an ephemeral Diffie-Hellman key exchange, and instead use RSA or Elliptic Curve Diffie-Hellman to perform the key exchange?

This could be because the client did not list a DHE (ephemeral Diffie-Hellman) cipher suite in priority, or because the server decided to pick a different kind of key agreement algorithm.

If this is the case, we would observe an exchange that we could not spy on or tamper with via our DHE backdoor.

Dorey et al. discovered that an active man-in-the-middle could change that by tampering with the original client's ClientHello message to single-out a DHE cipher suite (removing the rest of the non-DHE cipher suites) and forcing the key exchange to happen by way of the Diffie-Hellman algorithm.

This works because there are no countermeasures in TLS 1.2 (or prior) to prevent this to happen.

Final notes

My original white paper has been updated to reflect Dorey et al.'s developments while minimally changing its structure (to retain chronology of the discoveries). You can obtain it here.

Furthermore, let me mention that the new version of TLS —TLS 1.3— will fix all of these issues in two ways:

  • A server now signs the entire observed transcript at some point during the handshake. This successfully prevents any tampering with the ClientHello message as the client can verify the signature and make sure that no active man-in-the-middle has tampered with the handshake.
  • Diffie-Hellman groups are now specified, exactly like how curves have always been specified for the Elliptic Curve variant of Diffie-Hellman. This means that unless you are in control of both the client and the server's implementations, you cannot force one or the other to use a backdoored group (unless you can backdoor one of the specified group, which is what happened with RFC 5114).
Best crypto blog posts of 2017 David Wong Wed, 27 Dec 2017 17:05:28 +0100 http://www.cryptologie.net/article/435/best-crypto-blog-posts-of-2017/ http://www.cryptologie.net/article/435/best-crypto-blog-posts-of-2017/#comments Hello hello,

Merry christmas and happy new year. We're done for the year and so it is time for me to write this blog post (I did the same last year by the way).

I'll copy verbatim what I wrote last year about what makes a good blog post:

  • Interesting. I need to learn something out of it, whatever the topic is. If it's only about results I'm generally not interested.
  • Pedagogical. Don't dump your unfiltered knowledge on me, I'm dumb. Help me with diagrams and explain it to me like I'm 5.
  • Well written. I can't read boring. Bonus point if it's funny :)

Without further adue, here is the list!

That's it!

Have I missed something? Please tell me in the comments.

If you want more links like these, be sure to subscribe to my link section here on this website.

See you in 2018!

SHAKE and SP 800-185 David Wong Thu, 14 Dec 2017 16:22:01 +0100 http://www.cryptologie.net/article/434/shake-and-sp-800-185/ http://www.cryptologie.net/article/434/shake-and-sp-800-185/#comments I've talked about the SHA-3 standard FIPS 202 quite a lot, but haven't talked too much about the second function the standard introduces: SHAKE.

fips 202

SHAKE is not a hash function, but an Extendable Output Function (or XOF). It behaves like a normal hash function except for the fact that it produces an “infinite” output. So you could decide to generate an output of one million bytes or an output of one byte. Obviously don't do the one byte output thing because it's not really secure. The other particularity of SHAKE is that it uses saner parameters that allow it to achieve the desired targets of 128-bit (for SHAKE128) or 256-bit (for SHAKE256) for security. This makes it a faster alternative than SHA-3 while being a more flexible and versatile function.

SP 800-185

SHAKE is intriguing enough that just a year following the standardization of SHA-3 (2016) another standard is released from the NIST's factory: Special Publication 800-185. Inside of it a new customizable version of SHAKE (named cSHAKE) is defined, the novelty: it takes an additional "customization string" as argument. This string can be anything from an empty string to the name of your protocol, but the slightest change will produce entirely different outputs for the same inputs. This customization string is mostly used as domain separation for the other functions defined in the new document: KMAC, TupleHash and ParallelHash. The rest of this blogpost explains what these new functions are for.


Imagine that you want to send a message to your good friend Bob. You do not care about encrypting your message, but to make sure that nobody modifies the message in transit, you hash it with SHA-256 (the variant of SHA-2 with an output length of 256-bit) and append the hash to the message you're sending.

message || SHA-256(message)

On the other side, Bob detaches the last 256-bit of the message (the hash), and computes SHA-256 himself on the message. If the obtained result is different from the received hash, Bob will know that someone has modified the message.

Does this work? Is this secure?

Of course not, I hope you know that. A hash function is public, there are no secrets involved, someone who can modify the message can also recompute the hash and replace the original one with the new one.

Alright, so you might think that doing the following might work then:

message || SHA-256(key || message)

Both you and Bob now share that symmetric key which should prevent any man-in-the-middle attacker to recompute that hash.

Do you really think this is working?

Nope it doesn't. The reason, not always known, is that SHA-256 (and most variants of SHA-2) are vulnerable to what is called a length extension attack.

You see, unlike the sponge construction that releases just a part of its state as final output, SHA-256 is based on the Merkle–Damgård construction which outputs the entirity of its state as final output. If an attacker observes that hash, and pretends that the absorption of the input hasn't finished, he can continue hashing and obtain the hash of message || more (pretty much, I'm omitting some details like padding). This would allow the attacker to add more stuff to the original message without being detected by Bob:

message || more || SHA-256(key || message || more)

Fortunately, every SHA-3 participants (including the SHA-3 winner) were required to be resistant to these kind of attacks. Thus, KMAC is a Message Authentication Code leveraging the resistance of SHA-3 to length-extension attacks. The construction HASH(key || message) is now possible and the simplified idea of KMAC is to perform the following computation:

cSHAKE(custom_string=“KMAC”, input=“key || message”)

KMAC also uses a trick to allow pre-computation of the keyed-state: it pads the key up to the block size of cSHAKE. For that reason I would recommend not to come up with your own SHAKE-based MAC construction but to just use KMAC if you need such a function.


TupleHash is a construction allowing you to hash a structure in an non-ambiguous way. In the following example, concatenating together the parts of an RSA public key allows you to obtain a fingerprint.


A malicious attacker could compute a second public key, using the bits of the first one, that would compute to the same fingerprint.

fingerprint attack

Ways to fix this issue are to include the type and length of each element, or just the length, which is what TupleHash does. Simplified, the idea is to compute:

    input=“len_1 || data_1 || len_2 || data_2 || len_3 || data_3 || ..."

Where len_i is the length of data_i.


ParallelHash makes use of a tree hashing construction to allow faster processing of big inputs and large files. The input is first divided in several chunks of B bytes (where B is an argument of your choice), each chunk is then separately hashed with cSHAKE(custom_string=“”, . ) producing as many 256-bit output as there are chunks. This step can be parallelized with SIMD instructions or other techniques available on your architecture. Finally each output is concatenated and hashed a final time with cSHAKE(custom_string=“ParallelHash”, . ). Again, details have been omitted.

Real World Crypto 2018 David Wong Mon, 11 Dec 2017 18:52:30 +0100 http://www.cryptologie.net/article/433/real-world-crypto-2018/ http://www.cryptologie.net/article/433/real-world-crypto-2018/#comments Real World Crypto, the best crypto/security conference, will start next January in Zurich. It is about to sell out so grab a ticket quickly!

You might think it's too crypto-y for you, or not real-world enough. Think again. I'm not the only one who think this conference is awesome. ]]>
Introducing Disco David Wong Fri, 08 Dec 2017 10:39:28 +0100 http://www.cryptologie.net/article/432/introducing-disco/ http://www.cryptologie.net/article/432/introducing-disco/#comments Yesterday I gave a talk at Black Hat about my recent research with Disco. (Thanks Bytemare for the picture.)

black hat disco

I've introduced both the Strobe protocol framework and the Noise protocol framework in the past. So I won't go over them again, but I advise you to read these two blog posts before reading this one (if you care about the technical details).

As a recap:

1. The Strobe protocol framework is a framework to build symmetric protocols. It's all based on the SHA-3 permutation (keccak-f) and the duplex construction. Codebase is tiny (~1000LOC) and it can also be used to build simple cryptographic operations.

strobe commands

2. The Noise protocol framework is a framework to build things like TLS. It's very simple and flexible, and I believe a good TLS alternative for today.

noise nx

Looking at the previous diagram representing the NX handshake pattern of Noise (where a client is not authenticated and a server sends its long-term static key as part of the handshake) I thought to myself: I can simplify this. For example, you can see:

  • an h value absorbing every messages being sent and received, and being used to authenticate the transcript at some points in the handshake.
  • a ck value being used to derive keys from the different key exchanges happening during the handshake.

These things can be simplified greatly by using Strobe to get rid of all the symmetric tricks, while at the same time getting rid of all the symmetric primitives in use (AES-GCM, SHA-256, HMAC and HKDF).

This is exactly how I came up with Disco, merging Noise and Strobe to simplify the former.


Here is the simplification I made of the previous diagram. We're using Strobe's functions like send_CLR, recv_CLR and AD to absorb messages being sent or received as well as the output of the different key exchanges. We're also using send_AEAD and recv_AEAD to encrypt/decrypt and authenticate the whole transcript up to this point (these functions don't exist in Strobe, but they are basically send/recv_ENC followed by send/recv_MAC).

disco nx

You can see that everything looks suddenly much more simple to implement or understand. send_CLR, recv_CLR and AD are all functions that do the same thing: they XOR the input with the rate (public part) of our strobe state. It is so elegant that I made another diagram showing what is really happening in this diagram with Strobe. (Something that I obviously couldn't have done with AES-GCM, SHA-256, HMAC and HKDF.)

duplex view disco nx

You can see two lines here in the StrobeState. The capacity (secret part) is on the left and the rate (public part) is on the right. Most things get absorbed by just XORing the input with the public part (of course if we reach the end of the public part, we would permute and start on a new block like we do for hashing with the sponge construction).

When we send or receive encrypted data, we also need to do a little dance and first permute the state to produce something based on all of the data we've previously absorbed (including outputs of diffie-hellman key exchanges). This output is random enough to allow us to encrypt (or decrypt) by just imitating one-time pads and stream ciphers: XORing the randomized public part with a plaintext (or a ciphertext).

authenticated encryption

Once this is done, the state is permuted again to generate a new series of random numbers (in the public part) which will be the authentication tag, allowing us to authenticate everything that was absorbed previously.

After that the state can be cloned and differentiated to allow both sides to encrypt data on different channels (unless they want to use the same channel by taking turns). Strobe functions can continue to be used to continuously encrypt/decrypt application data and authenticate the whole transcript (starting from the first handshake message to the last message sent or received).

no iv

I thought the idea was worth exploring, and so I wrote a specification and proposed it as an extension to Noise. You can read it here). Details are still being actively discussed on the Noise mailing list. Major points of contention seem to be that the Strobe functions used do not introduce intra-handshake forward-secrecy, and that the post-handshake API does not mirror the Noise's post-handshake API one (nonce-based) by default. The latter is on purpose to avoid having to setup nonces and keeping track of them if not needed (because messages are expected to arrive in order thanks to the transport protocol used underneath disco).


After all of that, I figured out that I would probably have to be the first one to implement Disco. So I went ahead and first implemented a Noise-based protocol in Golang (that I call NoisePlugAndPlay). I tested it with test vectors and other libraries to get a minimum amount of confidence in what I did, then I decided to implement Disco on top of it. The protocol I created is called libdisco.


It's more than just a protocol to encrypt communications though. Since I'm using Strobe, I can also make it a symmetric cryptographic library without adding much lines of code (100 wrapping lines of code to be exact).

Of course it's all experimental. I will not recommend anyone to use this in production.

Instead, play with it and appreciate the concepts. Down the line, this could really be the modern alternative to TLS we've been waiting for (of course I'm biased here). But the road is long and paved with issues that need better be fixed before entering a stable version.

If I caught your interest, go take a look at www.discocrypto.com.

My talk on SHA-3 and derived functions at DEF CON 25 David Wong Sat, 02 Dec 2017 11:52:06 +0100 http://www.cryptologie.net/article/431/my-talk-on-sha-3-and-derived-functions-at-def-con-25/ http://www.cryptologie.net/article/431/my-talk-on-sha-3-and-derived-functions-at-def-con-25/#comments The talk I gave at defcon this year is online

SHA-3 vs the world @ OWASP London David Wong Thu, 23 Nov 2017 22:49:16 +0100 http://www.cryptologie.net/article/430/sha-3-vs-the-world-owasp-london/ http://www.cryptologie.net/article/430/sha-3-vs-the-world-owasp-london/#comments I just gave a talk at OWASP London on SHA-3 and derived functions + derived protocols.

It was apparently the first crypto talk in 5 years so I'm glad I revived this part of OWASP =)

Speaking at OWASP David Wong Wed, 22 Nov 2017 19:38:07 +0100 http://www.cryptologie.net/article/429/speaking-at-owasp/ http://www.cryptologie.net/article/429/speaking-at-owasp/#comments I'll be speaking at OWASP London tomorrow. It will be the same talk I just gave at Defcamp two weeks ago, and it will be the last time I give this talk.

It's sold out, but there will be a live streaming posted somewhere (maybe on their facebook page?).

After that, I will be talking at Black Hat Europe about Disco and libDisco. Stay tuned.

Ethernaut CTF walk through David Wong Tue, 21 Nov 2017 14:45:07 +0100 http://www.cryptologie.net/article/428/ethernaut-ctf-walk-through/ http://www.cryptologie.net/article/428/ethernaut-ctf-walk-through/#comments This is a walk through of the Ethernaut capture-the-flag competition where each challenge was an ethereum smart contract you had to break.

I did this at 2am in a hotel room in Romania and ended up not finishing the last challenge because I took too long and didn't want to re-record that part. Basically what I was missing in my malicious contract: a function to withdraw tokens from the victim contract (it would have work since I had a huge amount of token via the attack). I figured I should still upload that as it might be useful to someone.

Noise Plug-and-play Implementation in Golang David Wong Sat, 04 Nov 2017 15:42:50 +0100 http://www.cryptologie.net/article/427/noise-plug-and-play-implementation-in-golang/ http://www.cryptologie.net/article/427/noise-plug-and-play-implementation-in-golang/#comments I wrote an implementation of Noise in Go. I've already talked about it here but I've made some progress towards a more usable library.

It is now a real protocol built from the Noise protocol framework!

Noise doesn't work right off-the-bat because it does not have a length field in its messages. This means that two problems can arise:

  • if a noise message is fragmented, the receiver will not be able to know and will not be able to parse the received fragments
  • if noise messages are received concatenated to one another, noise will interpret that as one big message and the integrity verification of the encrypted message (via GCM or Poly1305) will fail

In different words, without an indication of a length, noise cannot know where a message stops. Messages can get fragmented by middleboxes, and can get concatenated just because of latency or the way the other peer send its messages. In lab condition this might not be a problem, but in real life without a framing protocol below Noise things will fail quickly.

This is why by default, you can't implement the components of the Noise specification and expect it to work. Having said that, with this minimal addition of a length field things do work!

But that's not the only problem that the specification fails to tackle. The other problem is the authentication of static public keys.

You see, in Noise you have many different ways of doing handshakes (named Noise_XX, Noise_KN, ...), and some of them do not require one of the peer's authentication. Kind of like the typical browser ↔ webserver scenario where only the webserver will authenticate itself via a certificate (and perhaps the browser will later authenticate itself via credentials in a form). Some patterns that you should never use fail to authenticate both side (Noise_NN) and that is why I haven't implemented them. But for patterns that do authenticate one of the side (or both), problems arise: the Noise specification does not have any safeguards in its algorithms to prevent you from failing to authenticate the other side of the connection.

This means that if you implement Noise following the specification, patterns like Noise_XX where both sides require authentication will happily go through without caring about authenticating anything. This leads to trivial active man-in-the-middle attacks.

What I've done is that:

  • if the pattern in use have your peer send a static public key to the other one, I require you to provide a proof when setting up your peer. Think about a signature from an authoritative root signing key.
  • if the pattern in use have your peer receive a static public key from the other one, I require you to provide a callback function to verify that key, optionally using payloads sent during the handshake (for example, a certificate containing a signature).

To make things truly plug-and-play, I've created helper functions that let you generate an authoritative root signing key and create proofs or callbacks for a set of parameters. I've written some documentation here that should get you started in no time. If things are broken (this is a beta) or not clear please let me now.

And again, don't use this in production.

The biggest achievement of this implementation though is the fact that it is implementing the net.Conn interface of the Golang standard library. This mean that if you're already using networking code in your Go application, you can just replace your net.Conn or tls.Conn with noise.Conn and things will continue to work seamlessly.

Speaking at Defcamp David Wong Wed, 01 Nov 2017 18:07:50 +0100 http://www.cryptologie.net/article/426/speaking-at-defcamp/ http://www.cryptologie.net/article/426/speaking-at-defcamp/#comments I'll be at Defcamp talking about SHA-3 (the standard), as well as its derived functions and protocols. It's happening next week in Bucharest. If you're around there hit me up!


Publishing my smart contract on the main ethereum network David Wong Fri, 27 Oct 2017 11:29:31 +0200 http://www.cryptologie.net/article/425/publishing-my-smart-contract-on-the-main-ethereum-network/ http://www.cryptologie.net/article/425/publishing-my-smart-contract-on-the-main-ethereum-network/#comments warning: as this is a proof of concept to see if 4chan could be implemented on the blockchain, some people might post shocking pictures or videos on there. At the time of the writing nothing "bad" has happened, but take precautions if you're planning to take a look at it :)

This is part II of Writing a DAPP for the Ethereum block chain I guess (where I previously said I would not publish this smart contract on the main network).

Pulling the entire Ethereum blockchain took me all afternoon. The thing is taking 29GB of disk space at the moment.

I sent ~20USD worth of ether (0.10 ether) from Coinbase to my real Mist wallet and prepared to see how much it would cost to deploy my smart contract. Surprisingly it was cheap! It cost me 0.007715952 ETHER which is ~2USD (around 1 million unit of gas at 0.008 ether per million gas) to deploy my contract to 0x470fb19D08c3d2eB8923A31d1408c393Dab09ccF an address computed out of my keypair and a nonce. I do not own its associated private key because I simply will never need it.

etherscan source code

To make sure the smart contract's code was properly open sourced on etherscan.io I had to put the source code there and provide the used compiler's version and the ABI encoded arguments to the controller. The ABI encoded arguments are just the 0-padded hexadecimal encoing of the arguments. I had two uint256 as arguments to my FiveMedium() constructor: the fee to post a thread and the fee to reply to a thread.


I decided to set the creation of a thread around 1$ and replying to a thread around 10 cents. It was then time to push the button and publish it.


And voila! You can access the DAPP on davidwong.fr/FiveMedium.

Note: the mandatory gas cost to post or reply on a thread seems to be around 0.30$. This has influenced me to lower down the contract fees to approach the gas fees.

Writing a DAPP for the Ethereum block chain David Wong Thu, 26 Oct 2017 14:29:56 +0200 http://www.cryptologie.net/article/424/writing-a-dapp-for-the-ethereum-block-chain/ http://www.cryptologie.net/article/424/writing-a-dapp-for-the-ethereum-block-chain/#comments warning: as this is a proof of concept to see if 4chan could be implemented on the blockchain, some people might post shocking pictures or videos on there. At the time of the writing nothing "bad" has happened, but take precautions if you're planning to take a look at it :)

The FiveMedium DAPP browsed from the Mist wallet


I've been dabbing in smart contract security (see my video here) and I found it natural to try and do a DAPP (decentralized application) myself. How hard can it be?

3.5 days later I've got back into Javascript after many years; I've learned Vue.js (kind of, my code is really ugly) and I've created my first DAPP!

First thing I'll have to say: it's hella fun.

Javascript has gone a long way and the Vue.js framework is just great! I've tried using React but I found it less developer-friendly, harder to learn and lacking in terms of template. It just didn't click. I guess coming from HTML first (and jQuery later) the Vue.js framework just makes more sense to me. It's all about having fun and I wasn't having any with React.

I still want to create, modify and query things the jQuery way, but I'm getting used to the javascript modernities (querySelector, arrow functions, ...) and the Vue.js way. I like it. It will take some time to get rid of my old habits and re-think the way I write front end code but I like it.

Writing the smart contract is quite straight forward. It's 128 lines of Solidity code, but most of it are comments (yes I comment my code). At one point I should publish it on etherscan.io because this is best practice. It's not compiled with the last version of Solidity (boooo!) because I deployed it via Mist and Mist doesn't have the last version of Solidity.

solidity code

Writing the dapp with Vue.js and the web3.js API (the javascript library to interact with the blockchain via an ethereum node) is pretty straight forward as well. The learning curve is not bad and there are tons of resources for beginners. That is, until you test your dapp with a real wallet like the Metamask wallet (integrated as a browser plugin) or the official Mist wallet (Electron app). Different wallets offer different functions and versions of web3 (how it works: they inject the web3 object in your document and you can use it directly from your javascript webapp). They also (for the most part) refuse any synchronous calls on the web3 API without really providing ways for you to debug what is not synchronous in your call. A lot of functions have to be replaced for the asynchronous variants, any async/await has to disappear and you enter callback hell. Not fun.
The worst is that the documentation gets sparser and sparser as you enter the world of real DAPPs. You understand that things are changing really fast, that wallets will soon stop supporting web3.js and that a real API will be provided at some point. Everything is way more experimental than I had thought.
On top of that, Metamask doesn't let you watch for events yet, so say goodbye to your DAPP being "live" for their users.

To make the app offline, meaning browsable without a wallet, I use Infura. You basically just have to switch the url of the node to the ones Infura gives you, and web3 will be able to interact with it the same way it interacts with a real node. This is because the standard works via normal Json-RPC routes using the Json way to structure queries and responses. Unfortunately, like Metamask, Infura doesn't let you listen to events so the app is browsable, but not live.

I haven't taken the time to publish the smart contract on the real ethereum network yet. It's sitting on Rinkeby which is a test network where you can get ethers for free. I'm not going to get rich on a test network, and some of my friends are eyeballing me for this decision (I see you jc) but this is fun and I want people to try it for free :)

Is it hard? No but it's annoying. First I need to pull up the whole Ethereum blockchain.

As of April 19th, 2017, my blockchain size is 23.5 GB total.

from this Quora answer

Second, I need some ethers, and buying ethers from the UK is hard. Of course I already have some (I wouldn't be writing anything about ethereum if I wasn't invested), but I had to go through weeks of research to buy them. (If you're looking for an easy way, learn from my wasted time: transfer money on a Revolut account, change it to euro, do a free SEPA transfer to Kraken, buy ethers there.)

Anyone can replicate my work. The DAPP is client-side code (javascript) so anyone can download it and run it on their own page. the contract is also up there on the blockchain, it's public stuff. I don't really like this, but it is how Ethereum works. If I someday drop the page from the internet, anyone can get it and run it. Run it on their own server, but also run it locally from their own machine.

If you want to see how it works without getting a wallet:

But I recommend you to give a try to this new technology!

Download Mist, set the network to Rinkeby, grab some free ethers from the faucet there and browse to my DAPP FiveMedium.

Have fun!

PS: yes this is heavily inspired by 4chan.

Attacks on Ethereum Smart Contracts David Wong Wed, 11 Oct 2017 22:45:37 +0200 http://www.cryptologie.net/article/423/attacks-on-ethereum-smart-contracts/ http://www.cryptologie.net/article/423/attacks-on-ethereum-smart-contracts/#comments I just made a video covering common attacks on Ethereum's smart contracts. I used live0verflow's techniques to record and edit this one so it's going to feel different from the others :) It's a tl;dr of A survey of attacks on Ethereum smart contracts by Nicola Atzei and Massimo Bartoletti and Tiziana Cimoli.

ps: many thanks to Matthew Di Ferrante for the help!

Posters, figures and graphics David Wong Sun, 08 Oct 2017 18:51:32 +0200 http://www.cryptologie.net/article/422/posters-figures-and-graphics/ http://www.cryptologie.net/article/422/posters-figures-and-graphics/#comments I've polished the design of this blog a bit (with flexbox and css-grid!) and it should look a bit cleaner :)

I've also created a page for graphics. I only have 3 at the moment, but I know that PHD students often present posters like these at conferences so if you know any (or if you have one yourself) and you want me to showcase it there send me a message!

crypto graphics

Two Student Tickets for Black Hat Europe in December 2017 David Wong Wed, 04 Oct 2017 11:47:02 +0200 http://www.cryptologie.net/article/421/two-student-tickets-for-black-hat-europe-in-december-2017/ http://www.cryptologie.net/article/421/two-student-tickets-for-black-hat-europe-in-december-2017/#comments I'm giving a talk at Black Hat Europe in a few months, and thus I was given two tickets for students to come attend the conference for free.

Anyone interested?

EDIT: no more tickets! If you really want to go to Black Hat, I'd advise you to contact directly other speakers as every BH speaker is given 2 free pass for students.

Go Assembly by Example David Wong Fri, 01 Sep 2017 16:43:25 +0200 http://www.cryptologie.net/article/420/go-assembly-by-example/ http://www.cryptologie.net/article/420/go-assembly-by-example/#comments In my quest to understand Go Assembly better, I forked Go by Example and created my own version for Go Assembly.

You can check it out here, and someone already translated it in Chinese here.


Zero'ing memory, compiler optimizations and memset_s David Wong Fri, 25 Aug 2017 14:42:19 +0200 http://www.cryptologie.net/article/419/zeroing-memory-compiler-optimizations-and-memset_s/ http://www.cryptologie.net/article/419/zeroing-memory-compiler-optimizations-and-memset_s/#comments

tl;dr: use this code

When a program uses a secret key for some cryptographic operation, it will store it somewhere in memory. This is a problem because it is trivial to read what has been previously stored in memory from a different program, just create something like this:

#include <stdio.h>

int main(){
    unsigned char a[5000];
    for(int i = 0; i < 10000; i++) {
        printf("x", a[i]);

This will print out whatever was previously there in memory, because the buffer a is not initialized to zeros. Actually, C seldom initializes things to zeros, it can if you specifically use something like calloc instead of malloc or static in front of a global variable/struct/...

EDIT: as Fred Akalin pointed to me, it looks like this is fixed in most modern OS. Colin Perceval notes that there are other issues with not zero'ing memory:

if someone is able to exploit an unrelated problem — a vulnerability which yields remote code execution, or a feature which allows uninitialized memory to be read remotely, for example — then ensuring that sensitive data (e.g., cryptographic keys) is no longer accessible will reduce the impact of the attack. In short, zeroing buffers which contained sensitive information is an exploit mitigation technique.

This is a problem.

To remove a key from memory, developers tend to write something like this:

memset(private_key, 0, sizeof(*private_key));

Unfortunately, when the compiler sees something like this, it will remove it. Indeed, this code is useless since the variable is not used anymore after, and the compiler will optimize it out.

How to fix this issue?

A memset_s function was proposed and introduced in C11. It is basically a safe memset (you need to pass in the size of the pointer you're zero'ing as argument) that will not get optimized out. Unfortunately as Martin Sebor notes:

memset_s is an optional feature of the C11 standard and as such isn't really portable. (AFAIK, there also are no conforming C11 implementations that provide the optional Annex K in which the function is defined.)

To use it, a #define at the right place can be used, and another #define is used as a notice that you can now use the memset_s function.

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdlib.h>

// ...

#ifdef __STDC_LIB_EXT1__
memset_s(pointer, size_data, 0, size_to_remove);

Unfortunately you cannot rely on this for portability. For example on macOS the two #define are not used and you need to use memset_s directly.

Martin Sebor adds in the same comment:

The GCC -fno-builtin-memset option can be used to prevent compatible compilers from optimizing away calls to memset that aren't strictly speaking necessary.

Unfortunately, it seems like macOS' gcc (which is really clang) ignores this argument.

What else can we do?

I asked Robert Seacord who always have all the answers, here's what he gave me in return:

void *erase_from_memory(void *pointer, size_t size_data, size_t size_to_remove) {
    if(size_to_remove > size_data) size_to_remove = size_data;
    volatile unsigned char *p = pointer;
    while (size_to_remove--){
       *p++ = 0;
    return pointer;

Does this volatile keyword works?

Time to open gdb (or lldb) to verify what the compiler has done. (This can be done after compiling with or without -O1, -O2, -O3 (different levels of optimization).)

Let's write a small program that uses this code and debug it:

int main(){
    char a[6] = "hello";
    printf("%s\n", a);
    erase_from_memory(a, 6, 6);


  1. we open gdb with the program we just compiled
  2. we set a break point on main
  3. we run the program which will stop in main


We notice a bunch of movb $0x0 ...

Is this it? Let's put a breakpoint on the first one and see what the stack pointer (rsp) is pointing to.


It's pointing to the string "hello" as we guessed.


Going to the next instruction via ni, we can then see that the first letter h has been removed. Going over the next instructions, we see that the full string end up being zero'ed.


It's a success!

The full code can be seen here as an erase_from_memory.h header file that you can just include in your codebase:

#define __ERASE_FROM_MEMORY_H__ 1

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdlib.h> 
#include <string.h>

void *erase_from_memory(void *pointer, size_t size_data, size_t size_to_remove) {
  #ifdef __STDC_LIB_EXT1__
   memset_s(pointer, size_data, 0, size_to_remove);
   if(size_to_remove > size_data) size_to_remove = size_data;
     volatile unsigned char *p = pointer;
     while (size_to_remove--){
         *p++ = 0;
    return pointer;

#endif // __ERASE_FROM_MEMORY_H__

Many thanks to Robert Seacord!

PS: here is how libsodium does it

EDIT: As Colin Percival wrote here, this problem is far from being solved. Secrets can get copied around in (special) registers which won't allow you to easily remove them.