How not to QR (NHS COVID-19 App)

There is now law requiring (from 24th Sep) a QR code to be displayed in various premises so people can scan it in to the NHS COVID-19 App. See The Health Protection (Coronavirus, Collection of Contact Details etc and Related Requirements) Regulations 2020. The law has plenty of issues, but let's look at those QR codes...

It seems you can request the QR code poster for your venue, see here. The poster is emailed to you.

This is an example.

This is not how you do it - and I wonder if they got any technical advice from anyone on the matter first.

What's in this huge QR code?

The content of that QR code is: UKC19TRACING:1:eyJhbGciOiJFUzI1NiIsImtpZCI6IllycWVMVHE4ei1vZkg1bnpsYVNHbllSZkI5YnU5eVBsV1lVXzJiNnFYT1EifQ.eyJpZCI6IlJLWTMyV01SIiwib3BuIjoiUFVCTElDIFRFTEVQSE9ORSIsInZ0IjoiMDA1IiwicGMiOiJMRTE4M1RFIn0.ix66d7uRe_vhpB4BPb0Nzbq2vEC3IShdX7UOqfp0XVyg7YI88R_bOCY1DpgQZo9dy07xcga4e1MTmcKV9ZHi1A

The data contained is an RFC7515 JSON Web Signature (JWS) base64 coded string which contains:-

  • {"alg":"ES256","kid":"YrqeLTq8z-ofH5nzlaSGnYRfB9bu9yPlWYU_2b6qXOQ"}
  • {"id":"RKY32WMR","opn":"PUBLIC TELEPHONE","vt":"005","pc":"LE183TE"}
  • Binary signature

So what's wrong?

  • It is not user friendly - and requires the app installed first so you can use it (see below). This is perhaps the biggest issue. P.S. even with app installed, they have not hooked the QR code to the app, as they could have, so could be used from camera app - just lazy!
  • This QR code is far too big (i.e. dense)! The denser the code the harder to read reliably. There is no need for it to be this dense. A small code is quicker and easier to read.
  • One reason it is dense is poor choice of QR encoding options. It could be less dense with exact same content easily.
  • Another reason it is too dense is that the content is base64 coded JSON which itself contains base64 binary. This is crazy. The actual underlying data is quite small, and even signing it, it does not have to be anywhere near as big.
  • Another reason it is too dense is they have chosen to sign the data, which is pointless (see below)
  • Another reason it is too dense is they have chosen to encode some simple data (venue ID and name) in JSON, when there really is no need.
  • You have to use the gov web site to make the QR code, a large company could not, for example, automate making posters for all their sites centrally.
  • This is not actually a valid QR code! Yes, pretty much everything will read it, but the specification requires a 4 unit white space all around, and this does not have that - it has grey at 2 units and text within the whitespace area.
  • If you request a poster more than once for a venue, you get a different venue code, so the app will see each poster as a separate venue, it seems. I can easily see that happening as it may be easier to request a new poster than to find the PDF / email you previously saved if you need to print more.
  • Oh, and the instructions are to display the poster and ask people to scan it with the app, as soon as you get it, even though the app is not actually working yet, so people cannot scan it with the app!
  • The poster has no link to where to get the app, just the store you have to search, and guess what, searching does not work (depending on exactly what you type):-

In summary this is thrown together with some standard libraries and very little actual thought - is not even a valid QR code, and is going to be a mess with every waiter now expected to provide tech support on app installation on Android and iPhone to every customer that comes along - but this is very much what we have come to expect.

On another small technical point, base64 is a bad choice in a QR code. If designed for just the app to read, use binary coding which is 100% efficient (one dot per bit, before any ECC). Base64, however, uses byte coding, so 8 bits for each base64 character which holds 6 bits of data, so 75% efficient. If you don't want to use binary, use base32 which uses alphanumeric QR coding, 5½ bits for each character which holds 5 bits of data, so 91% efficient.

How to make it more user friendly

Many people have QR readers built in to their phone, for example an iPhone will pop up with a link from the camera app itself, so there is a really simple trick for this - make the QR code a URL which the app can read as data, but if used simply as a URL itself you end up going to a web site which redirects you to the app or the app store to download the app. The data can be after a # in the URL so not even sent to the server when used as a URL. This allows it to be used from the app or from the camera, and helps for people that don't yet have the app, and those that mistakenly did not realise they have to launch the app first. It makes it a lot simpler to use.

It is not hard, basically, instead of UKC19TRACING:1:blah use https://c19qr.uk/#blah
(well, obviously, an nhs.uk domain would be used)

(Update: Just to clarify, the use of a URL at the start is not to make the QR code usage rely on an internet connection or a web site in any way. If the app is installed it would be used purely as a version/ID confirmation, like the UKC19TRACING:1: string, and the app would then just use the data in the QR code, not visit a web site. The URL is there to make it easy for people to use from camera, and to install the app in the first place).

Why is a "big" QR code a bad idea?

I have added this to clarify a little why the large / dense QR code is not ideal.

For a start, from a purely technical point of view, it is just unnecessary. You need some extra data to avoid confusion with other uses of QR codes, which is what the UKC19TRACING: is for, and ideally a version, which is what the 1: is for. Beyond that you just need the actual data (location code, postcode, and venue name, in this case). There is no need for extra syntax (e.g. JSON). Indeed, some careful choice of data (e.g. using digits, or upper case letters and digits) can make the QR coding even more efficient. But this is far from the only reason.

In ideal conditions it does not matter if you have a large/dense QR code. As someone that has been messing with barcodes for around 40 years, I have no trouble using a camera phone to read a barcode. I know what hoops the phone / software is going through to make it work and how best to position the camera. But I cringe watching people do this and struggle (notably, someone I know reading lottery ticket QR codes). They (understandably) don't know how these things work and will randomly try getting closer or further away, usually the wrong way, not waiting for camera to focus, etc, eventually reading the code.

The way it works is the camera has to be able to see the units, i.e. the black and white squares that make up the code. The camera itself has pixels (dots) with which it can see. If the camera was perfectly aligned and square you could read a QR code with one such pixel per unit, but that never happens, and in practice you need a lot more. Throw in the possibility of poor focus, glare and reflection from glass / perspex, dirty lens, and the QR code at an angle, and you need even more. Thankfully most modern camera phones are high resolution enough to cope and read a very large and dense QR code. Not all phone cameras are made equal and some are much lower resolution and slower to focus. Print quality also matters, and whilst most printers are very good, remember this is also intended to be used displayed on a screen. The QR code itself includes error correction which allows some imperfections and errors to be corrected, but this can only help so much.

Even so, perhaps the biggest issue with a large and dense QR code is the range of distance between the code and the camera. This is a thing I observe people struggling with, for some reason. With a low density QR code the camera can read it when it is small in the view of the camera. Also, when it is small in the view, they do not have to point directly at it, it can be off to one side, etc. With a large / dense QR code the camera needs to be closer, with the QR code filling more of the frame. So the usable distance range where the code can be read relates directly to how dense the QR code is. The more usable range, the easier it is for the user to get it right first time and not hold up a queue of people trying to get in to a bar.

Of course the other issue is how big you print it. The guideline for this is to print at least A4. Why? Because it is so dense. A smaller code could be printed much smaller and still be easy to use. I note, for example, Costa have small table menu cards with the check-in QR codes they used (which are nice and small) on them, and they are much smaller than A4.

One final reason is confusion and paranoia. I already see people on twitter asking what the hell is in this huge QR code. People are concerned that it obviously contains a lot of data and it is not obvious why. The whole project has suffered from privacy concerns already, and this does not help.

Why is signing daft?

Signing means that there is an extra chunk of information in the QR code (making it a lot bigger/denser) that ensures the data is genuine, i.e. that it definitely came from the government QR code generator web page. There are many good reasons to sign things, but not in this case.

The signing a tad daft as :-

  • Anyone can make a code for anywhere on the gov web site, and it gets signed.
  • You can copy a code from somewhere else and it is signed.
  • It makes the QR massive! and so harder to scan.
  • Obviously not done to try and avoid vulnerabilities, as one can get 
    سمَـَّوُوُحخ ̷̴̐خ ̷̴̐خ ̷̴̐خ امارتخ signed, no problem (which some may remember would crash iPhones).
  • To be quite frank, it would not be as fun making a barcode for Specsavers in Barnard Castle if the QR code was essentially just a postcode and name, and not government signed.
  • If, instead of signing, they just published a specification (as done by other countries), large companies with lots of sites could have made posters for all their venues centrally and easily as well as allowing individual posters via the gov website.

Whilst this is not quite the way the track and trace process works, if some establishment did not want to risk being shut down, they could put the barcode for a competitor, maybe with a vague establishment name in the QR code, so not obvious when using the app. The gov website lets you make a signed QR code for anywhere, and even if they did not, you can literally copy a signed QR code you can see anywhere, and it is still signed.

A further update (Oct 20th) shows the signing checking did not even work on Android!

And yes, they will sign almost anything. Emojis seem to be banned, but hieroglyphs are not. So I seem to have got the UK Government to digitally sign a penis!


How it could be a lot less dense, so easier to read

As an example, if I just include the actual data, and some sort of signature (an MD5 in this case, there are many ways to sign things), and a URL prefix to get the app (which acts as ID/version), you could make a code like this... Way less dense, and easier to use.

If you don't sign the data (and why would you?)

All that is really needed in the code is the location, a postcode with DPS, e.g. LE183TE9Z, or maybe just a UPRN (Unique Property Reference Number), e.g. 100032050996. The postcode/DPS may be better as you can then quote the venue postcode in the app. You probably do need the venue name as well to quote in the app. That is not a lot of data that is actually needed.

If you do that, you can make a code like this which has a URL, UPRN, and premises name in it, and is way less dense and easier to scan.

With just a postcode/DPS it is possible to go even smaller!

Is the app OK though?

Just to be clear, this is criticism of the QR code not the track and trace app. There is a blog on that which is quite interesting, but does not explain why they felt it necessary to sign the QR codes, or why they did not make them a URL format for easy access to the app. Here: https://www.ncsc.gov.uk/blog-post/nhs-test-and-trace-app-security-redux (the previous app described here https://www.ncsc.gov.uk/blog-post/security-behind-nhs-contact-tracing-app)

P.S. I have a QR code generation library available free on GitHub. here.


  1. Thanks; interesting stuff and good points made.

    The NCSC link you have at the end is for the previous (now defunct) NHSX app.

    Happily there's an NCSC post about the new one too, which also mentions the QR codes:


    (As an aside, it's quite instructive to compare the arguments used previously with the ones used now.)

  2. It looks like they used the QR code from the New Zealand app developed by a company "rush digital" rather than from scratch looking at the architecture diagram.

    1. It looks like they started with the NZ scheme, some of their press photos feature a QR code with the NZCOVIDTRACER: prefix but this design is their own. The NZ ones aren't using JWS.

  3. Interestingly the law requires people to scan the QR code but not to install the app. So legally you can scan it with the normal barcode reader, do nothing with the data and then not give your details.

    1. It doesn't even require that, as far as I can tell.

      There's a requirement to display a QR code, a requirement to request details if someone doesn't scan a QR code (eg. no smartphone) but no requirement on the person entering the store to scan the code or give these details, it's still only a request.

      But if the store didn't want to let you in without it (which they might, even though the law doesn't compel them to) you could indeed scan the QR code with the builtin one in the phone and be perfectly compliant also.

    2. I did just this at a NT place today!
      Held up my phone for camera to read it, said got it, clicked the pop up (got the string of code), kept walking, cancelled it all!

  4. Presumably because your Egyptian penis is allowed, all the standard URL exploits for homographs or spaces would also work so you could do a more high-tech version of D0wning Street to either work against a competitor or spread your business's risk.

  5. What problem did they think they were solving with the signature? Sounds like they don't know what they're doing (I mean no surprise there).

    I wonder where else this particular key is used.

  6. =So whats wrong=
    "requires the app installed first"
    it requires the app is because of privacy. If it was a url, they can't prove
    they don't store the data
    "the qr code is too big/dense"
    QR codes have EC, but they can be read in the same time anyway
    "poor choice of QR encoding options"
    EC means its easier to read
    "too dense/base64 coded json"
    There is no need for compression its so small
    "signing data is pointless"
    (see below.)
    "encoding simple data in JSON"
    Why not, and its easier
    "you have to use the gov website"
    So they can sign it, you can request multiple codes anyway, venues are
    "its not valid"
    QR codes don't have a validity check. there is protocol (it even uses)
    but thats not important
    "you get a different venue code"
    Well, they are *different venues*, you can correlate data yourself
    (it's public which venues are dangerous)
    "scan it as soon as you get it"
    This is common sense. Have it ready for when it releases,so they can use it
    "its hard to search for it"
    That's not NHS' fault, its Itunes' fault
    "its thrown together with very little actual thought"
    its shown that theres thought, i.e. signing for safety, EC for ease of use,
    not using internet
    They took time to address the privacy concerns
    "every waiter expected to provide tech support"
    You can't do that in the next lockdown
    Common sense, no one would ask that from a waiter
    You can go to the nhs website
    =make it more user friendly=
    "built in camera"
    its not hard to install an app
    "signing is daft"
    It's not daft. It means the app doesn't need internet to check it. It means
    there aren't scams. It means you don't have to worry.
    Again, it's not much denser, and its barely harder to scan a large QR code
    "you can copy a code"
    bluetooth tracking still works properly...
    so they can have unique locations in the same postcode
    density is not a problem
    =is that app ok=
    "does not explain"
    why not sign them, plus they dont need that in the blog, it says the

  7. You seem to be missing a lot of points. Just a few to answer quickly...

    URL can have # so not sent
    Time is not issue, getting barcode in view and low res cameras can be, as is where you can put it (eg Costa have their small barcodes on small notices on the tables as well)
    Validity as per the specification for QR codes. These do not actually meet the specification.
    Common sense and instructions differing is the issue
    Signing has nothing to do with needing Internet to check!
    Copying codes has nothing to do with Bluetooth working, it is one reason signing is a tad silly
    Unique locations could still be done in a much smaller/ simpler code
    Signing does not mean there are not “scams” (what few scams could be done)
    As for tech support, if someone that is struggling at the front of a queue then staff will try to help.
    You can absolutely not clue on UX, clearly.

    But thanks for your comments.

  8. Not much clue on base64 encoding either; he thinks it is a compression... it is actually an expansion. It makes it 25% bigger! Might be required to encode some Welsh (or Maori) names.

    1. QR can hold UTF-8 directly with the right ECI header. They manage a hieroglyph dick :)

  9. Is there a UKC19Tracing app for windows or Mac OS?

  10. Is there a UKC19Tracing app for windows (.exe) or Mac OS (package or disc image)

  11. Thanks so much for this analysis. I became curious about why the code was so long when at a pub yesterday - we noticed people having to stand back to get the whole code in view, and also some people couldn't scan it at all because of a shadow (they had to move the poster in the end). I wasn't at all surprised to see it just seems to be a case of the same old "government IT project" syndrome

  12. Rev, thanks for the deep-detailed analysis. I too was GEEKING OUT over those super dense QR codes? What are they scanning... aircraft engine parts?

    I suggest the use of the ECDSA/ES256 signature was in response to data privacy fears. Although built on New Zealand's tried and tested system, the English and Welsh signed implementation yields a tiny payload for an oversized signature bloat. btw nowhere online I could find an official specification for the UK QR codes, only reversed engineered hacks.

    JSON web signatures have always been a 'thing' that Microsoft pushes, but no-one else can understand why it's better than everything else that does signing? Almost all people who do data for a living would have kept the gross payload simple; the blocks would be big enough to scan under those reflective plastic sheets that most venues keep their (photocopied) A4 posters under. Isn't that what testing in-the-wild was all about?

    Your point about the waistfull use of BASE64URL is the most serious. It's a critical flaw that takes the edge off of this "world beating" track and trace system. But on a project that had already spent millions of pounds delivering another I.T. failure, the new inner circle would have had no desire to expose their source code to peer review; as they did on Github with the version 1-or-2 Beta.

    So why not not put that NHS QR code inside a rainbow? Just a thought.

    Stay safe.

    Andy @ tier3

  13. It turns out the signing verification was actually broken on Android anyway initially, making it even more pointless: https://www.zofrex.com/blog/2020/10/20/alg-none-jwt-nhs-contact-tracing-app/

  14. I have written up my own frustrations as an issue here https://github.com/nhsx/covid-19-app-android-ag-public/issues/34 and linked to this blog.


Comments are moderated purely to filter out obvious spam, but it means they may not show immediately.

TOTSCO changing the rules again

One of the big issues I had in initial coding was the use of correlationID on messages. The test cases showed it being used the same on a se...