Corona-Warn-App in den Nachrichten

Weltweit geht es tatsächlich jetzt richtig los.

Christian Drosten / faz.net / welt.de / zeit.de

Wenn 75 Prozent aller Menschen die App benutzen, könnte das die Todesfälle um bis zu 78 Prozent verringern, die Infektionsrate gar um 81 Prozent. […] Tausende von Leben könnten gerettet werden. 

Corona-Warn-Apps: Lebensretter oder nicht? (heise.de)

Exposure Notification API Implementations

Diagnosis Keys Parsing

from datetime import datetime, timezone
from json import loads
from os import unlink
from random import random, randrange
from tempfile import NamedTemporaryFile
from time import time
from ssl import CERT_NONE, create_default_context
from urllib import request
from zipfile import ZipFile

print( '''

    https://blinkything.org/diagnosis-keys-parsing

    download the attached TemporaryExposureKeyExport.proto and run
    # protoc --python_out=$(pwd) TemporaryExposureKeyExport.proto

    after that, tun this script to download all available exposure keys,
    parse the protobuf format and print "human readable" contents

''' )

from TemporaryExposureKeyExport_pb2 import TemporaryExposureKeyExport

results = TemporaryExposureKeyExport()

# stupid Apple stupid Mac software
insecure = create_default_context()
insecure.check_hostname = False
insecure.verify_mode = CERT_NONE

# https://blinkything.org/diagnosis-keys-distribution
address = "https://svc90.main.px.t-online.de/version/v1/diagnosis-keys/country/DE/date"

# https://developer.apple.com/documentation/exposurenotification/enexposureinfo/3583716-transmissionrisklevel
# https://developers.google.com/android/exposure-notifications/exposure-notifications-api#data-structures
levels = [ "Unused", "Confirmed / Low risk", "Confirmed / Standard risk", "Confirmed / High risk", "Clinical diagnosis", "Self report", "Negative case", "Recursive case", "Custom" ]

for day in sorted( [ datetime.fromtimestamp( int( time() - day * 24 * 60 * 60 ) ).strftime( "%Y-%m-%d" ) for day in range( 1, 14 ) ], key = lambda entry : randrange( -1, 2 ) ) :
    timeslices = loads( request.urlopen( "%s/%s/hour" % ( address, day ), context = insecure ).read() )
    for hour in sorted( timeslices, key = lambda entry : randrange( -1, 2 ) ) :
        file = NamedTemporaryFile( suffix = ".zip" )
        ignore = file.write( request.urlopen( "%s/%s/hour/%s" % ( address, day, hour ), context = insecure ).read() )
        ignore = results.ParseFromString( ZipFile( file ).read( "export.bin" )[ 16: ] )

for entry in results.keys :
    start = datetime.fromtimestamp( entry.rolling_start_interval_number * 600, tz = timezone.utc )
    key = str( "" ).join( [ "%02X" % int( value ) for value in entry.key_data ] )
    risk = entry.transmission_risk_level
    if entry.transmission_risk_level < len( levels ) :
        risk = levels[ entry.transmission_risk_level ]
    print( start.strftime( "%Y-%m-%d" ), key, risk )
2020-07-28 DBD4FBDB25E192331403C01856E28E4C Custom
2020-07-31 DD1126751C3F7D0C94E78313478EC079 Negative case
2020-07-30 DDA92095040304E8F3194398B1756E5F Custom
2020-07-24 DE7A1BEFA3647A1711EF86405E146A35 Confirmed / Low risk
2020-07-22 DEFD32D1A693DAB2C5DF84967AD268EF Confirmed / Low risk
2020-07-21 DF794C176F664E3EDD6634295EA5823A Confirmed / Low risk
2020-07-29 DF91AD4A61756C9AFAE85CE68F908AEF Custom
2020-07-27 E1A1818AEAB09F3765C6F4750DD2A28D Self report
2020-07-31 E2596B474956B0680F7DF97A471256FA Negative case
2020-07-31 E32B95A338D293F37B2CA335532BC716 Negative case
2020-07-20 E47CDA3C8780BF5162BA7BF59EA852AE Confirmed / Low risk
2020-07-29 E490C2D8464CDF2AC3845AD39E455C90 Custom
2020-07-30 E58BEA941CCDA715CA7D89A51B46AF57 Custom
2020-07-31 E58CB52DE34B548F526DCF6F9317A31D Negative case
2020-07-21 E712149A08A4089A8FADBBDCBA247CBA Confirmed / Low risk
2020-07-23 E831310321B5635F45372FC803A41D79 Confirmed / Low risk
2020-07-28 E9927B7A1C1B499676D1800813197788 Custom
2020-07-30 E9CFA64B7540AD606DEA33EC796102EC Custom
2020-07-29 EA97B428133D82CA545BD7C7ED77482D Custom
2020-07-30 EC0636792FD774462F3415D881FF7AB3 Custom
2020-07-21 ED5EDFC74E3F9A0B290D1CE3F83BAC17 Confirmed / Low risk
2020-07-31 ED82A6FD074E06BDE14C040A7CAFA89F Negative case
2020-07-24 EE155EDEF5B24510D5979124A9CFC2BC Confirmed / Low risk
2020-07-20 EE7246DF8AAAC8CF0CC87327E1D316C3 Confirmed / Low risk
2020-07-20 EF854F51CB5E74F29BD55962771D8DAA Confirmed / Low risk
2020-07-31 EFAD52A8303390513804CA110D3E355A Negative case
2020-07-30 F01BC8D86B49A7F6DF9E027D451E6EA2 Custom
2020-07-20 F19C4467C6D897B7D89CEC827F93E70A Confirmed / Low risk
2020-07-27 F1A28E1BD67C722A1F38306B99F1EC40 Self report
2020-07-23 F2C2721978F11724763E7559D709F849 Confirmed / Low risk
2020-07-30 F2F56B1C03CDE73DD09B86EABDCF8FE7 Custom
2020-07-24 F3906C853A9860A385E45A9D25AA47E7 Confirmed / Low risk
2020-07-28 F4FD5834C929828330A0964E7B828635 Custom
2020-07-20 F5171741FA589E85FA503D9DB9D49268 Confirmed / Low risk
2020-07-20 F6BA2A9DEEAA5CCBB41121BA25DA2F4B Confirmed / Low risk
2020-07-25 F6C913867DEBD152AC5BF7465CE747E0 Confirmed / Low risk
2020-07-25 F854B1ACD4642DABEFBED10DB70F1141 Confirmed / Low risk
2020-07-21 F866DE1B3537C2ACE8EF3708350F4D6F Confirmed / Low risk
2020-07-27 F8EF13EDD4D1A785CBA927588A9FDFF9 Self report
2020-07-22 F8EF4192FC288A25B8D5EF4D8C50FC05 Confirmed / Low risk
2020-07-22 F94D16245E962E3301004D459B177E7E Confirmed / Low risk
2020-07-31 F96328E487724BC805B8BD49F6ED4DC2 Negative case
2020-07-30 FA84B29369EABF0E9C8758722DB40F7E Custom
2020-07-26 FBDAB57DAB26581FE6D0590BDA2D4C6B Confirmed / High risk
2020-07-27 FC08BD6A9CC59DE8C12CDD1388971D35 Self report

Diagnosis Keys Distribution

#!/bin/bash
DAY=0
# https://github.com/corona-warn-app/cwa-server/blob/master/services/distribution/src/test/java/app/coronawarn/server/services/distribution/objectstore/publish/PublishedFileSetTest.java
URL="https://svc90.main.px.t-online.de/version/v1/diagnosis-keys"
while true ; do
  DAY=$(expr $DAY + 86400)
  DATE=$(date -r $(expr $(date +%s) - $DAY) +%Y-%m-%d)
  # https://github.com/corona-warn-app/cwa-server/blob/master/services/distribution/api_v1.json#L229
  for HOUR in $(curl --silent "$URL/country/DE/date/$DATE/hour" | egrep -o "[0-9]+") ; do
    FILENAME="diagnosis_keys_DE_$DATE_$HOUR"
    # https://github.com/corona-warn-app/cwa-server/blob/master/services/distribution/api_v1.json#L289
    curl --silent "$URL/country/DE/date/$DATE/hour/$HOUR" --output "$FILENAME.zip"
    unzip -q "$FILENAME.zip"
    rm "$FILENAME.zip"
    # https://github.com/google/exposure-notifications-server/tree/main/examples/export#inspecting-an-export
    tail +17c < export.bin  | protoc --decode=TemporaryExposureKeyExport TemporaryExposureKeyExport.proto > "$FILENAME.txt"
    rm export.*
    # https://developers.google.com/android/exposure-notifications/exposure-key-file-format
    head -20 "$FILENAME.txt"
    echo "..."
    echo
  done
done       
start_timestamp: 1596517200
end_timestamp: 1596520800
region: "DE"
batch_num: 1
batch_size: 1
signature_infos {
  verification_key_version: "v1"
  verification_key_id: "262"
  signature_algorithm: "1.2.840.10045.4.3.2"
  1: "de.rki.coronawarnapp"
}
keys {
  key_data: "\002\306\311\0249\"0ya\275\017\2548\233\022\275"
  transmission_risk_level: 8
  rolling_start_interval_number: 2660400
  rolling_period: 144
}
keys {
  key_data: "\004X4o\321^r:\344\343\222)\222Df\177"
  transmission_risk_level: 6
...

“Smartphone contact tracing failed”

Governments in Europe and North America need to consider critically why they are failing to engage the public. Lack of trust is one obvious issue which has limited the adoption of smartphone apps, but those apps don’t appear to have been designed to be effective for Public Health either. It would appear that no government has thought this out properly yet.

(from “Smartphone contact tracing has failed everywhere”)