Cherry referring to my last name Forward and Reverse Engineering

Deriving Safety Numbers from Signal Ed25519 Keys

Just in case anybody needs this (for whatever odd reason), the following is a small python script deriving the fingerprint from the public part of a Signal identity key and the phone number it is tied to. Two per-identity fingerprints are sorted and concatenated to form the per-conversation safety number that is displayed in the verification screen in the app. The following python code is in accordance with the implementation in fingerprint/ of libsignal-protocol-java on github:

#!/usr/bin/env python3

import hashlib, base64


def fingerprint_hash(pub_key, stable_id):
    assert len(pub_key) == 1 + 32 # 1 byte type + 256 bit key
    assert pub_key[0] == DJB_TYPE

    md = int.to_bytes(FINGERPRINT_VERSION, 2, "big") + pub_key + stable_id
    for _ in range(5200):
        md = hashlib.sha512(md + pub_key).digest()
    return md

def to_disp_hash(md):
    return [ int.from_bytes(md[5*off:5*off+5], "big") % 100000 for off in range(6) ]

if __name__ == "__main__":
    # get this from a Signal database (exported backup or desktop client),
    # typically a base64 string starting with an uppercase 'B'
    pub_key = base64.b64decode("BYN0Y1LdkF98c3GOCZRkhAObwMSr6Yg0WlDH43qLwrZi")
    # "+<country-code><phone-number>"
    stable_id = b"+491749091317"

    disp_hash = to_disp_hash(fingerprint_hash(pub_key, stable_id))

    print(" ".join([ f"{h:05}" for h in disp_hash ]))