Form spec proposal: allow signed content to verified using form logic

I'm currently working on a use case where data is pulled out of a QR code during form entry. This is possible using the barcode scanner and the various XForm substring methods. We also need to verify that the QR code is genuine however. So that this is possible, the QR code contents is signed using a private key (using Ed25519) intended for later verification with a public key.

It's currently possible to build an external app for Collect that could receive the QR contents, verify the signature for a given public key and then return the "message" portion (the stuff we actually want from the QR code). However, it'd be much smoother for the data collectors if this could happen as part of a calculation.

To achieve this, I'm proposing a new function that receives a Base64 encoded string and public key and then returns the message (non-signature) portion of the contents if the signature is valid and an empty string if not:

extract-signed(contents, public-key)

This function would initially support a standard 64 byte Ed25519 signature, but I don't see why a third argument couldn't be added later to support other algorithms. I've gone through a few iterations on how best to solve this in XForms, so here's some notes to hopefully give you some context on how I got here:

  • I'd initially looked at using base64-decode and then splitting the string so that we could just add a boolean "verify" function. This doesn't work in our case (and I'm sure a lot of others) however, as the signature is binary and converting to a UTF-8 string corrupts it. Also, because UTF-8 is variable length, we aren't able to grab the first 64 bytes.
  • We could solve the above problems by introducing a function that allows us to decode Base64 content to a binary, but I don't think there's currently a concept of passing binary around (in the JavaRosa implementation it would byte[]).This does mean that we need to handle Base64 decoding in extract-signed, but given how common it is to Base64 encode a QR code (especially in cases where you need to deal with binary data) I don't feel like it's too unreasonable.

I'm going to start work on a PR contribution to JavaRosa as I already have a working example implementation, but I'm definitely open to feedback here! That goes doubly for the name of the function which I'm not overly happy with!