Ave's tech notes

This is a list of quirks I spotted on eMRTDs that I'm posting to try and help out anyone else who is trying to parse them. It's a list I will continue updating, probably.

As I've spotted these while implementing hf emrtd set of commands on Proxmark3, they're all fixed there.

Authentication protocol

  • Really old Belgian passports don't enforce any authentication.
  • German Personalausweises, even those issued before 2018, enforce PACE. They do not, however, contain the chip inside icon at the time of writing (though they will get it on August 2021).
  • German Aufenhaltstitels, even those issued before 2018, enforce PACE. They DO have the chip inside icon, and had them while enforcing PACE all the way back to 2015.

MRZ and EF_DG1 (TD3 – Passport Size)

  • For the optional field, some countries use a number even if it is empty (all <), and some use <. (CH etc)
  • Germany uses D for country code (D<< on MRZ) instead of DEU. This is the only instance where a country code deviates from ISO 3166-1 alpha-3. (This is also documented on ICAO 9303 p3 and German Passport Act Law.)

MRZ and EF_DG1 (TD1 – ID Size)

  • Old (2017) Turkish IDs use German-style ascii-ification while new ones (2018 and after) don't. (2017: OEZDIL, 2018 and after: OZDIL)
  • Turkish IDs have one preceding < before the ID number on optional field (<1234568902<<<).
  • Germany uses D for country code (D<< on MRZ) instead of DEU. This is the only instance where a country code deviates from ISO 3166-1 alpha-3. (This is also documented on ICAO 9303 p3 and German Passport Act Law.)


  • Belgian (and french?) passports have some tags with len=0, specifically on localized names (5F 0Eh) and alternative names (5F 0Fh under A0h).
  • Hungarian passports have non-localized names (5F 0Fh) on EF_DG11.
  • Turkish IDs and Passports (pre and post NVI) have full dates of birth (5F 2Bh) as ASCII.
  • Belgian and French passports have full dates of birth (5F 2Bh) as bytes.


  • Turkish IDs and Passports (pre and post NVI) have issuance dates (5F 26h) as ASCII (Example: 20201231 or 50 48 50 48 49 50 51 49h).
  • Belgian and French passports have issuance dates (5F 26h) as bytes (Example: 20 20 12 31h).


  • Turkish IDs and Passports don't include 05 00h at the end of hash algorithm (on descriptors such as 06 09 60 86 48 01 65 03 04 02 01 05 00h for SHA256), while some do.
  • USA Passports use 80h for field length of the main EF_SOD sequence, declaring the size as having an indefinite length as per BER.
  • Different countries have different times between the document issuance date and certificate start date, between the document expiry date and the certificate end date. Netherlands seems to be 3 and 6 days respectively for Netherlands, and 45 and 45 days respectively for Turkey.

Future edit:

I was informed that rlottie exists (which is used by Telegram and Discord): https://github.com/Samsung/rlottie

It comes with a built-in GIF converter called lottie2gif, but that does not support transparency.

I ended up making a (shitty) tool called LFE based on that that, which does the job of extracting each frame as PNGs with transparency. You can then replace the puppeteer-lottie-cli steps to equivalents with lfe.

I've run benchmarks of converting 30 files (alongside some other processing), and it ended up getting me over 3x speedups.


real    6m10.508s
user    2m3.647s
sys     0m19.909s


real    1m59.302s
user    1m56.607s
sys     0m5.522s


This is a blog post intended to explore the current options out there regarding Lottie->GIF/APNG conversions and go into what I personally ended up doing.

Wait, what is a “Lottie” again?

So, this is a little convoluted, but bear with me.

“Bodymovin” is a project created by Hernan Torrisi in 2015 that allows people to export After Effects projects as special JSON files, and originally, to use them on web.

Lottie seems like it was originally a project by airbnb introduced around early 2017* to bring facemovin to more platforms , but it seems like at some point facemovin became “Lottie-Web”, though it seems like it's still maintained by Hernan Torrisi.

Lottie is used by a number of large companies. Discord and Telegram recently started using Lottie for their animated stickers. (Though it's worth noting that Telegram actually uses a fork)

I personally dislike it. Sure, it may be smaller than an APNG, but it also makes my CPU a lot sadder than one, especially when there's several on the screen at once.

The options out there right now


When I first tested python-lottie, it crashed when trying to convert images:


They corrected this bug since then, but it still is a little buggy for converting to GIFs:

It needs work on the real world lottie files I tested (like the one above), but it is still quite promising. If you're reading this far into the future, you might want to try that before you deal with the messy conversion I talk about doing in this blog post.


puppeteer-lottie-cli seemed a lot more promising as it ran a headless browser (and a lot less desirable as it's much heavier as a result), but outputs were... buggy, especially on parts with transparency:

Lottiefiles.com converter

The lottiefiles.com converter kept popping up here and there and people seemed to be rather happy about it, but it provided no API.

However, this got me wondering... how does that tick behind the scenes?

The deep dive

So, the first thing I ended up doing was searching “Lottiefiles github” to see if their website source code was public, and while it wasn't...

One of their forks gave me a really good pointer: https://github.com/LottieFiles/puppeteer-lottie

I suddenly realized that puppeteer-lottie had the potential to give me what I need, and started taking a look at the changes of this fork of puppeteer-lottie.

Not much was added, just a way to grab specific frames (and a fix for that).

I got the idea of just extracting frames and going off of those, and then stumbled upon this issue asking for APNG support. What's more interesting, however, was the fact that the issue body included a way of extracting each frame separately, which isn't something I realized I could do before.

I quickly did that, and took on the task of converting it into a GIF myself.

Not a lot interesting happened there, but after some fiddling with tools, I ended up with a pretty good way of converting Lotties to GIFs.


The way I currently convert lotties to GIFs is first extracting them into each separate frame (with a fixed size):

puppeteer-lottie -i "infilename.json" -o "frame-%d.png" --width 500

Then looking at the framerate inside the lottie file (“fr” field in the json), and converting it to an intermediary GIF with ffmpeg...

ffmpeg -y -framerate "frameratefromjson" -i "frame-%d.png" -filter_complex "[0:v] fps=50,split [a][b];[a] palettegen [p];[b][p] paletteuse" "intermediary.gif"

And finally, using imagemagick to do a -dispose Background pass for it to render properly everywhere..

convert -dispose Background "intermediary.gif" "final.gif"

This does sadly get rid of transparency, but it also gets rid of all the glitches:

And so, that's it! The best way of converting Lotties to GIFs at the moment, at least in my opinion.


*: I'm not entirely sure about when exactly Lottie popped up, and the official blog post does not include a date, but the file upload date is 01/2017. The second blog post has a cover image upload date of 08/2017, and refers to Lottie's release as “6 months ago”.

So, I've spent some of my free time in the last 2 days working on LasagnaTel, Lasagna Ltd's internal phone network, and did some small improvements. One of the changes I wanted to also do was fixing DTMF tones (to only have them inband).

Over the last couple months, I've been thinking on and off wondering if my specific cisco phone supports custom ringtones ever since I saw linuxgemini set their ringtone to Nokia Arabic Ringtone, but never really bothered with it, but...

While I was trying to edit the config files to fix the DTMF issue, I saw a file called Ringtones.xml on my tftp server from the base set of files I used from an internet resource months ago, and decided to take a look. It had two “custom” ringtones in it (“custom”, as they were the default tunes I believe, but the files were hosted on the server, and weren't on the phone itself), and when I opened the ringtone menu on the phone, those were displayed, and when I hit play, those did play.

So I ended up trying to add that again.

Just like everything else with these damn phones though, resource was sparse. I ended up not finding too many resources, but with technical information (on what I need to convert my files to) from linuxgemini and this ancient cisco document (archive.lavatech.top, archive.org) and some other information on The Internets™, I was able to figure out how to convert files:

ffmpeg -i in.wav -t 00:00:20.0 -ar 8000 -ac 1 -f mulaw out.raw

As you can see, I'm cutting the files to their first 20 seconds, as that's the limit. Any longer, and it errors. That's the thing that gave me the most trouble.

After that, all I had to do was copying it to the tftp server root, adding it to the Ringlist.xml:

    <DisplayName>CTU 24</DisplayName>
    <DisplayName>Old Telephone</DisplayName>
    <DisplayName>Nokia Arabic</DisplayName>

and re-opening the ringtone menu on the phone. It does take a couple seconds for it to load, and even more seconds for it to download the ringtone the first time you hit play, but it ended up working perfectly once it downloaded it once.

Here's a video demonstration:

Anyhow, that now works! Enjoy your enterprise shitposting!

I've been looking for a cold storage solution to use with LavaTech backups for some while now, and was planning to use online.net C14 (now C14 Classic). Well, they just re-released it under Scaleway, and I've decided to take on the task of getting cold storage working.

I use rclone for a lot of purposes, and for the task at hand, it's what I'll be using to move data from Backblaze B2 hot storage to C14 cold storage.

As C14 in rclone is still C14 classic, and as Scaleway C14 implement an S3-like API (it's not a standard or a protocol as they claim here), I decided to get it working.

Instructions or whatever

  • Get an API Key from the credentials page
  • Edit ~/.config/rclone/rclone.conf and add this (replace <access key> with your actual key, same for secret key. Change all instances of fr-par to nl-ams if you want to use the AMS region):
type = s3
provider = Other
env_auth = false
access_key_id = <access key>
secret_access_key = <secret key>
region = fr-par
endpoint = https://s3.fr-par.scw.cloud
location_constraint = fr-par
acl = private
bucket_acl = private
chunk_size = 25M
upload_concurrency = 100
storage_class = GLACIER
  • Save and exit. After this, you can verify that it works by creating a bucket on desktop and then running a command like rclone copy testfile c14-cold:/bucketname and then checking the UI:

Copied file on c14 website

Ps. This uploads directly to Cold Storage without requiring any moving from the UI. If you want to change that, remove the storage_class = GLACIER line from config.