Of course state actors can add a backdoor to Signal

Instant messaging apps with end-to-end encryption love to brag about how they protect their users’ privacy, even in the face of mandatory decryption laws. Signal’s homepage claims:

we can’t read your messages or listen to your calls, and no one else can either.

But if you’re one of the many users installing Signal in a typical fashion (via the App Store on an iPhone), it can certainly be modified to send your messages to someone else, and you will be none the wiser. This kind of modification is referred to as a “backdoor”.

This post focuses on backdoors that software developers can be compelled to create under the Australian Assistance and Access Act. The Act allows various state agencies in Australia to compel industry to help safeguard national security, the interests of Australia, and enforce Australian and foreign criminal law. An obvious and intended application is to gain access to communications of people under state surveillance. This legislation was passed back in 2018, so it’s not new, but the implications it has for privacy are still relevant today.

Signal devs on backdoors

I’m going to pick on Signal a lot in this post, because I’m familiar with it. A lot of the problems I describe would apply equally to Telegram, WhatsApp, and other messaging apps with end-to-end encryption. While I’ll describe ways the developers could do better, know that the real problem here is legislation like the Assistance and Access Act.

Back in 2018, Joshua Lund (jlund@) of Signal brags in a blog post reacting to the Act, “we can’t include a backdoor in Signal”. He goes on to say:

Reproducible builds and other readily accessible binary comparisons make it possible to ensure the code we distribute is what is actually running on user’s devices. People often use Signal to share secrets with their friends, but we can’t hide secrets in our software.

However, if you actually dig into the details of Signal’s issue for reproducible iOS builds and the thread the discussion was moved to, it’s apparent that verifying a Signal binary installed via the App Store is actually quite complex. Apple modifies the binaries it serves via the App Store, so verification involves backing up the iPhone with iTunes to get the .ipa file, unpacking it, decrypting the binary using a jailbroken device, and comparing that to a known-good binary. Theoretically the Signal devs (or someone else with a jailbroken phone) could publish a list of known-good hashes of the Apple-modified .ipa files, but they don’t. They don’t even make the binaries they upload to the App Store easily available: try finding them from the Signal download page or the GitHub releases page.

Most users are taking the claims on Signal’s home page that “we can’t read your messages or listen to your calls, and no one else can either” at face value, without building from source or going through extra steps to verify binaries. These claims are wrong: there is a real risk of backdoored binaries when trusting the App Store.

Continue reading “Of course state actors can add a backdoor to Signal”

Slow WordPress Memcached Object Cache with App Engine

I thought it would be a good idea to add a persistent WordPress object cache to this blog, to reduce page load times and increase resilience to spikes in traffic. So I added the WordPress Memcached Object Cache drop-in (AKA wp-memcached), and enabled the legacy App Engine Memcache API. However, adding the Memcache object cache increased page load times by 10s or more! Looking into it further, while the App Engine diagnostics reported a high (90%+) cache hit ratio, the drop-in was getting 0% cache hits. The drop-in was adding keys to the cache only for them not to be found in subsequent reads. There were also hundreds of SQL queries that did not occur with WordPress’s default (request-scoped) object cache.

With some additional debugging and perusing of the source code of PECL’s official Memcached module, the App Engine SDK, and the wp-memcached code, I figured out what was going on and how to fix it.

Continue reading “Slow WordPress Memcached Object Cache with App Engine”

macOS incorrect colours on external monitor

I bought a new OLED monitor, which worked great with my Windows machine, but when I connected it to my MacBook Air and MacBook Pro via a USB-C to HDMI* adapter the colours all looked very wrong.

Blacks were tinted pink/fuchsia/magenta, whites were tinted yellow/green, all colours look wrong, yet the macOS UI is still legible. Turns out the issue is that macOS thinks the monitor is a TV and encodes colours as YCrCb (or YPbPr) instead of RGB.

photo of Big Sur wallpaper with bad colour encoding
How the Big Sur wallpaper looked
photo of colour gamut with bad colour encoding
The colour information is all there, just… wrong.

Solution

There appear to be distinct fixes for Intel versus Apple Silicon machines.

Intel macs

For Intel macs, the solution is to override the EDID information via a plist, with a base64-encoded EDID payload. I originally tried using patch-edid.rb to generate one, but ended up following this procedure instead:

  1. Dump the EDID data using ioreg -l -d0 -cr -c AppleDisplay. Find the “IODisplayEDID” key for my external monitor. For me, I could exclude the built-in monitor using its IOClass of “AppleBacklightDisplay”. ioreg prints the EDID data as a hex string, which I copied into its own text file. You’ll also want to note the values of “DisplayProductID” and “DisplayVendorID”.
  2. Convert the hex EDID payload to a binary file, e.g. cat edid.txt | xxd -r -p > edid.bin.
  3. Open the binary EDID file with AW EDID Editor. Disable any toggles that mention YCrCb or YCC (there were several of these in the CEA extension block). Slightly confusingly, for me there were also some disabled controls in the EDID Base block under “Color Encoding Formats” (but it turns out it didn’t matter that YCrCb 4:4:4 was still enabled there). Save the EDID file.
  4. Convert the revised binary EDID file to base64 using base64 -i edid.bin.

  5. Fill out the $VARS in the property list template below with the DisplayProductID (as decimal), DisplayVendorID (as decimal) and an arbitrary name string (which will show up in System Settings and such).
  6. Encode the vendor ID and product ID into the override path as hex, e.g.: printf /Library/Displays/Contents/Resources/Overrides/DisplayVendorID-%x/DisplayProductID-%x $VENDORID $PRODUCTID. Move the plist there.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>DisplayProductName</key>
  <string>$NAME can be whatever</string>
  <key>IODisplayEDID</key>
  <data>$EDID as base64</data>
  <key>DisplayVendorID</key>
  <integer>$VENDORID as decimal</integer>
  <key>DisplayProductID</key>
  <integer>$PRODUCTID as decimal</integer>
</dict>
</plist>

Apple Silicon (M1, M2, etc.)

For Apple Silicon, the solution is to override the LinkDescription in /Library/Preferences/com.apple.windowserver.displays.plist. See Force-RGB-color-on-M1-Mac for a great description of this method.

Process

Figuring out the fix was a bit of a process for me: my first few searches suggested it could be a cable problem, but I verified the cables worked just fine with the same monitor and other computers. It also didn’t look like the typical colour aberrations when you’re just “missing” a colour channel. Then I thought it was a problem with the USB-C to HDMI adapter I was using. When I stumbled on old (2013) blog and forum posts I was initially skeptical that it was the same issue or that the workarounds would still work. But it turns out that it is a macOS bug that’s been around for 10+ years, and the old workarounds still work!

* I know DisplayPort would be better, but I want to leave the monitor’s DisplayPort socket permanently plugged into my PC.
† I previously recommended patch-edid.rb for overriding the EDID information, but it drops critical resolution information, making it impossible for macOS to use the native resolution on my 2560×1440 monitor, leaving everything blurry.