Published April 1, 2020 | Version v2
Dataset Open

CVE-2019-1547: research data and tooling

Description

This dataset and software tool are for reproducing the research results related to CVE-2019-1547, resulting from the manuscript "Certified Side Channels". The data was used to produce Figure 4 in the paper and is part of the remote timing attack data in Section 4.1.

Data description

The file timings.json contains a single JSON array. Each entry is a dictionary representation of one digital signature. A description of the dictionary fields follows.

  • hash_function: string denoting the hash function for the digital signature.
  • hash: the output of said hash function, i.e. hash of the message digitally signed.
  • order: the order of the generator.
  • private_key: the ECDSA private key.
  • public_key: the corresponding public key.
  • sig_r: the r component of the ECDSA signature.
  • sig_s: the s component of the ECDSA signature.
  • sig_nonce: the ground truth nonce generated during ECDSA signing.
  • nonce_bits: the ground truth number of bits in said nonce.
  • latency: the measured wall clock time (CPU clock cycles) to produce the digital signature.

Prerequisites

OpenSSL 1.1.1a, 1.1.1b, or 1.1.1.c.

sudo apt install python-ijson jq

Data setup

Extract the JSON:

tar xf timings.tar.xz

Key setup

Generate the public key (public.pem here) from the provided private key (private.pem here):

$ openssl pkey -in private.pem -pubout -out public.pem

Examine the keys if you want.

$ openssl pkey -in private.pem -text -noout
$ openssl pkey -in public.pem -text -noout -pubin

Example: Verify key material

$ grep --max-count=1 'private_key' timings.json
  "private_key":"0x6b76cc816dce9a8ebc6ff190bcf0555310d1fb0824047f703f627f338bcf5435",
$ grep --max-count=1 'public_key' timings.json
  "public_key":"0x04396d7ae480016df31f84f80439e320b0638e024014a5d8e14923eea76948afb25a321ccadabd8a4295a1e8823879b9b65369bd49d337086850b3c799c7352828",
$ openssl pkey -in private.pem -text -noout
Private-Key: (256 bit)
priv:
    6b:76:cc:81:6d:ce:9a:8e:bc:6f:f1:90:bc:f0:55:
    53:10:d1:fb:08:24:04:7f:70:3f:62:7f:33:8b:cf:
    54:35
pub:
    04:39:6d:7a:e4:80:01:6d:f3:1f:84:f8:04:39:e3:
    20:b0:63:8e:02:40:14:a5:d8:e1:49:23:ee:a7:69:
    48:af:b2:5a:32:1c:ca:da:bd:8a:42:95:a1:e8:82:
    38:79:b9:b6:53:69:bd:49:d3:37:08:68:50:b3:c7:
    99:c7:35:28:28
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
    00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff
A:   
    00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
    00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:fc
B:   
    5a:c6:35:d8:aa:3a:93:e7:b3:eb:bd:55:76:98:86:
    bc:65:1d:06:b0:cc:53:b0:f6:3b:ce:3c:3e:27:d2:
    60:4b
Generator (uncompressed):
    04:6b:17:d1:f2:e1:2c:42:47:f8:bc:e6:e5:63:a4:
    40:f2:77:03:7d:81:2d:eb:33:a0:f4:a1:39:45:d8:
    98:c2:96:4f:e3:42:e2:fe:1a:7f:9b:8e:e7:eb:4a:
    7c:0f:9e:16:2b:ce:33:57:6b:31:5e:ce:cb:b6:40:
    68:37:bf:51:f5
Order: 
    00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff:
    ff:ff:bc:e6:fa:ad:a7:17:9e:84:f3:b9:ca:c2:fc:
    63:25:51
Cofactor:  0
Seed:
    c4:9d:36:08:86:e7:04:93:6a:66:78:e1:13:9d:26:
    b7:81:9f:7e:90

Three things to note in the output:

  1. The private key bytes match (private_key and priv byte strings are equal)
  2. The public key bytes match (public_key and pub byte strings are equal)
  3. This is an explicit parameters key, with the Cofactor parameter missing or zero, as described in the manuscript.

Example: Extract a single entry

Here we use the python script pickone.py to extract the entry at index 2 (starting from 0).

$ python2 pickone.py timings.json 2 | jq . > 2.json
$ cat 2.json 
{
  "public_key": "0x04396d7ae480016df31f84f80439e320b0638e024014a5d8e14923eea76948afb25a321ccadabd8a4295a1e8823879b9b65369bd49d337086850b3c799c7352828",
  "private_key": "0x6b76cc816dce9a8ebc6ff190bcf0555310d1fb0824047f703f627f338bcf5435",
  "hash": "0xf36d0481e14869fc558b39ae4c747bc6c089a0271b23cfd92bc0b8aa7ed2c3aa",
  "latency": 21565213,
  "nonce_bits": 253,
  "sig_nonce": "0x1b88c7802ea000ccb21116575c38004579b55f1f9c4f81ed321896b1e1034237",
  "hash_function": "sha256",
  "sig_s": "0x8c83417891547224006723169de9745a81fa8de7176428e1cd8e6110408f45da",
  "sig_r": "0xf922d9ba4f65d207300cc7eaaa15564e60a2b1f208d1389057ff1a1ec52dc653",
  "order": "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"
}

Example: Dump hash to binary file

Extract the hash field from the target JSON and dump it as binary.

$ sed -n 's/^  "hash": "0x\(.*\)",$/\1/p' 2.json | xxd -r -p > 2.hash
$ xxd -g1 2.hash
00000000: f3 6d 04 81 e1 48 69 fc 55 8b 39 ae 4c 74 7b c6  .m...Hi.U.9.Lt{.
00000010: c0 89 a0 27 1b 23 cf d9 2b c0 b8 aa 7e d2 c3 aa  ...'.#..+...~...

Note the xxd output matches the hash byte string from the target JSON.

Example: Dump signature to DER

The hex2der.sh script takes as an argument the target JSON filename, and outputs the DER-encoded ECDSA signature to stdout by extracting the sig_r and sig_s fields from the target JSON.

$ ./hex2der.sh 2.json > 2.der
$ openssl asn1parse -in 2.der -inform DER
    0:d=0  hl=2 l=  70 cons: SEQUENCE          
    2:d=1  hl=2 l=  33 prim: INTEGER           :F922D9BA4F65D207300CC7EAAA15564E60A2B1F208D1389057FF1A1EC52DC653
   37:d=1  hl=2 l=  33 prim: INTEGER           :8C83417891547224006723169DE9745A81FA8DE7176428E1CD8E6110408F45DA

Note the asn1parse output contains a sequence with two integers, matching the sig_r and sig_s fields from the target JSON.

Example: Verify the signature

We use pkeyutl here to verify the raw hash directly, in contrast to dgst that will only verify by recomputing the hash itself.

$ openssl pkeyutl -in 2.hash -inkey public.pem -pubin -verify -sigfile 2.der
Signature Verified Successfully

Note it fails for other hashes (messages), a fundamental security property for digital signatures:

$ dd if=/dev/urandom of=bad.hash bs=1 count=32
32+0 records in
32+0 records out
32 bytes copied, 0.00129336 s, 24.7 kB/s
$ openssl pkeyutl -in bad.hash -inkey public.pem -pubin -verify -sigfile 2.der
Signature Verification Failure

Example: Statistics

The stats.py script shows how to extract the desired fields from the JSON. It computes the median latency over each nonce bit length.

$ python2 stats.py timings.json
Len Median
238 20592060
239 20251286
240 20706144
241 20658896
242 20820100
243 20762304
244 20907332
245 20973536
246 20972244
247 21057788
248 21115419
249 21157888
250 21210560
251 21266378
252 21322146
253 21370608
254 21425454
255 21479105
256 21532532

You can verify these medians are consistent with Figure 4 in the paper.

The stats.py script can be easily modified for more advanced analysis.

Credits

Authors

  • Cesar Pereida García (Tampere University, Tampere, Finland)
  • Sohaib ul Hassan (Tampere University, Tampere, Finland)
  • Iaroslav Gridin (Tampere University, Tampere, Finland)
  • Nicola Tuveri (Tampere University, Tampere, Finland)
  • Alejandro Cabrera Aldaya (Tampere University, Tampere, Finland)
  • Billy Bob Brumley (Tampere University, Tampere, Finland)

Funding

This project has received funding from the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 804476).

License

This project is distributed under MIT license.

Files

README.md

Files (144.9 MB)

Name Size Download all
md5:cb135cd4cf7ee4e99625b910b5c3f883
1.6 kB Download
md5:b6b6465a3dbce306eec3ad531e4e4504
1.2 kB Download
md5:2c230951aae87a34bb52e454851a46d1
1.6 kB Download
md5:6357a88e6c4d81e039e1c13198b2264e
472 Bytes Download
md5:33195a0552d962d815938e0fab23d1ae
7.6 kB Preview Download
md5:7da7d4470ef175f98e267a7d12b33cab
2.0 kB Download
md5:93aac2e7568710873db9e66ba2ac7f97
144.9 MB Download

Additional details

Related works

Is cited by
Conference paper: arXiv:1909.01785 (arXiv)

Funding

SCARE – Side-Channel Aware Engineering 804476
European Commission