Secrets, Integrity and Imitation

I was recently reminded of a clever way to modify encrypted messages that I thought would be interesting to share. The main message is that encryption only provides the first of the following three properties:

  • Confidentiality: unauthorized actors cannot read the message
  • Integrity: unauthorized actors cannot secretly change the message
  • Authentication: the message was sent by the authorized party

The motivation for this post is a smart contract that we audited, which uses a commit-and-reveal scheme for voting. This means that participants first submit a hash of their ballot, and only reveal the ballot (which must match the hash to be considered valid) after all hashes have been collected. This prevents participants from deciding how to vote based on the running tally. However, it does not prevent someone from copying someone else’s hash commitment, and later “revealing” the same value, allowing them to blindly duplicate another voter’s ballot:

  1. Alice commits to ballotAlice with the commitment hash( ballotAlice )
  2. Bob sees this and commits to the same value
  3. Everyone else commits to their ballots
  4. Later, Alice reveals ballotAlice and everyone can confirm it matches her commitment
  5. Bob sees this and also “reveals” ballotAlice, which also matches his commitment, thereby duplicating Alice’s vote

To prevent duplication, we recommended that msg.sender be included in the hash (and validated after the ballot is revealed), binding each commitment to the voter that made it.

Things get more interesting in a different contract within the same system, where votes are encrypted with a key that will eventually be revealed (whether or not the original voter reveals it). As with the previous mechanism, this also allows participants to duplicate other ballots but interestingly, the same mitigation does not work. At an abstract level, this is because when encrypted data (or ciphertext) is modified, it still decrypts to something. In security lingo, encryption provides confidentiality but not integrity. Whether or not this fact is exploitable depends on the details of the system.

In this case, the smart contract uses a stream cipher, where the key stream is combined with the ballot (the plaintext) using the XOR operation:

ciphertext = key ⊕ ballot

Decryption is achieved by combining the result with the same key:

decrypted = key ⊕ ciphertext

          = key ⊕ (key ⊕ ballot)
          
          = (key ⊕ key) ⊕ ballot
          
          = 0 ⊕ ballot
          
          = ballot

If we append the voter’s address to the ballot before encryption, we can treat the result like two separate encryption operations:
split_encryption

This implies:

  1. If someone changes ciphervoter, it will create a corresponding change in the decrypted voter value.
  2. This will not affect the decryption of the ballot

Consider what happens if someone replaces the voter ciphertext with


cipher*voter = ciphervoter ⊕ voter ⊕ voter*  

Voter decryption becomes:


decryptedvoter = keyvoter ⊕ cipher*voter

              = keyvoter ⊕ ( ciphervoter ⊕ voter ⊕ voter* )
                
              = keyvoter ⊕ keyvoter ⊕ voter ⊕ voter ⊕ voter*
                
              = ( keyvoter ⊕ keyvoter ) ⊕ ( voter ⊕ voter ) ⊕ voter*
                
              = 0 ⊕ 0 ⊕ voter*
                
              = voter*

In other words, anyone who knows any section of the original plaintext can replace that section as desired, despite not knowing the encryption key, leaving all other sections intact. They could use this to replace the voter address with their own, bypassing the duplication protection.

In this particular case (but importantly, not in every case), this attack can be mitigated by simply appending a hash of the ballot and voter address to the plaintext.

7 Likes

Loved the writeup, @nikeshnazareth! This reminded me of a Matasano cryptochallenge, where an encrypted cookie with the role=user data had to be changed to a role=admin as an attacker, without knowing the encryption key (see here). It’s a fairly common mistake to assume that encryption can be used for integrity, but I had never seen this in the context of smart contracts. Cool article!

2 Likes