A.1. Esempio Dettagliato
Dettagliamo qui i valori intermedi ottenuti durante la generazione di k su un messaggio e una chiave di esempio. Utilizziamo una curva binaria perché quella curva specifica è standard e ha una lunghezza di ordine del gruppo (qlen) che non è un multiplo di 8; questo illustra i dettagli fini di come vengono eseguite le conversioni tra interi e sequenze di bit.
A.1.1. Coppia di Chiavi
Consideriamo ECDSA sulla curva K-163 descritta in [FIPS-186-4] (nota anche come "ansix9t163k1" in [X9.62]). La curva è definita su un campo GF(2^163): gli elementi del campo sono codificati in stringhe di 163 bit. L'ordine del punto base convenzionale è il valore primo:
q = 0x4000000000000000000020108A2E0CC0D99F8A5EF
che ha lunghezza qlen = 163 bit.
La nostra chiave privata è:
x = 0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F
La chiave pubblica corrispondente è il punto della curva U = xG. Questo punto ha due coordinate, che sono elementi del campo GF(2^163). Questi elementi possono essere convertiti in interi utilizzando la procedura descritta nella Sezione A.5.6 di [X9.62], producendo le due coordinate del punto pubblico:
Ux = 0x79AEE090DB05EC252D5CB4452F356BE198A4FF96F
Uy = 0x782E29634DDC9A31EF40386E896BAA18B53AFA5A3
A.1.2. Generazione di k
In questo esempio, utilizziamo la funzione hash SHA-256 [FIPS-180-4]. Il messaggio di input è la codifica UTF-8 della stringa "sample" (6 ottetti, cioè, 48 bit).
Il messaggio di input hashato h1 = SHA-256(m) è:
h1
AF 2B DB E1 AA 9B 6E C1 E2 AD E1 D6 94 F4 1F C7
1A 83 1D 02 68 E9 89 15 62 11 3D 8A 62 AD D1 BF
(32 ottetti; ogni valore di ottetto è elencato in notazione esadecimale).
Convertiamo la chiave privata x in una sequenza di ottetti utilizzando la trasformazione int2octets:
int2octets(x)
00 9A 4D 67 92 29 5A 7F 73 0F C3 F2 B4 9C BC 0F
62 E8 62 27 2F
Nota: Sebbene il valore specifico di x si adatterebbe numericamente in 160 bit, cioè, 20 ottetti, codifichiamo ancora x in 21 ottetti, perché la lunghezza di codifica è guidata dalla lunghezza di q, che è 163 bit.
Tronchiamo e/o espandiamo anche il messaggio hashato utilizzando bits2octets:
bits2octets(h1)
01 79 5E DF 0D 54 DB 76 0F 15 6D 0D AC 04 C0 32
2B 3A 20 42 24
I passaggi da b a g (vedere Sezione 3.2) calcolano quindi i valori per le variabili K e V. Queste variabili sono sequenze di 256 bit (la lunghezza di output della funzione hash, arrotondata per eccesso a un multiplo di 8). Riproduciamo qui i valori successivi:
V dopo il passaggio b:
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
K dopo il passaggio c:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
K dopo il passaggio d:
09 99 9A 9B FE F9 72 D3 34 69 11 88 3F AD 79 51
D2 3F 2C 8B 47 F4 20 22 2D 11 71 EE EE AC 5A B8
V dopo il passaggio e:
D5 F4 03 0F 75 5E E8 6A A1 0B BA 8C 09 DF 11 4F
F6 B6 11 1C 23 85 00 D1 3C 73 43 A8 C0 1B EC F7
K dopo il passaggio f:
0C F2 FE 96 D5 61 9C 9E F5 3C B7 41 7D 49 D3 7E
A6 8A 4F FE D0 D7 E6 23 E3 86 89 28 99 11 BD 57
V dopo il passaggio g:
78 34 57 C1 CF 31 48 A8 F2 A9 AE 73 ED 47 2F A9
8E D9 CD 92 5D 8E 96 4C E0 76 4D EF 3F 84 2B 9A
Nel passaggio h, eseguiamo il ciclo finale. Poiché utilizziamo HMAC con SHA-256, che produce 256 bit di output, e abbiamo bisogno solo di 163 bit per T, una singola invocazione HMAC produce il seguente T:
T (primo tentativo)
93 05 A4 6D E7 FF 8E B1 07 19 4D EB D3 FD 48 AA
20 D5 E7 65 6C BE 0E A6 9D 2A 8D 4E 7C 67 31 4A
che, quando convertito in un intero con bits2int, produce un primo candidato per k:
k1 = 0x4982D236F3FFC758838CA6F5E9FEA455106AF3B2B
Poiché quel valore è maggiore di q-1, dobbiamo ripetere il ciclo. Questo comporta prima il calcolo di nuovi valori per K e V:
nuovo K
75 CB 5C 05 B2 A7 8C 3D 81 DF 12 D7 4D 7B E0 A0
E9 4A B1 98 15 78 1D 4D 8E 29 02 A7 9D 0A 66 99
nuovo V
DC B9 CA 12 61 07 A9 C2 7C E7 7B A5 8E A8 71 C8
C9 12 D8 35 EA DD C3 05 F2 44 5D 88 F6 6C 4C 43
poi un nuovo T:
T (secondo tentativo)
C7 0C 78 60 8A 3B 5B E9 28 9B E9 0E F6 E8 1A 9E
2C 15 16 D5 75 1D 2F 75 F5 00 33 E4 5F 73 BD EB
e un nuovo candidato per k:
k2 = 0x63863C30451DADF4944DF4877B740D4F160A8B6AB
Poiché k2 è anche maggiore di q-1, ripetiamo nuovamente il ciclo:
nuovo K (2)
0A 5A 64 B9 9C 05 95 20 10 36 86 CB 6F 36 BC FC
A7 88 EB 3B CF 69 BA 66 A5 BB 08 0B 05 93 BA 53
nuovo V (2)
0B 3B 19 68 11 B1 9F 6C 6F 72 9C 43 F3 5B CF 0D
FD 72 5F 17 CA 34 30 E8 72 14 53 E5 55 50 A1 8F
T (terzo tentativo)
47 5E 80 E9 92 14 05 67 FC C3 A5 0D AB 90 FE 84
BC D7 BB 03 63 8E 9C 46 56 A0 6F 37 F6 50 8A 7C
e otteniamo finalmente un valore accettabile per k:
k = 0x23AF4074C90A02B3FE61D286D5C87F425E6BDD81B
A.1.3. Firma
Con la nostra chiave privata e il valore di k che abbiamo appena generato, possiamo ora calcolare la firma utilizzando i meccanismi ECDSA standard. Prima, viene calcolato il punto kG, e la coordinata X di quel punto viene convertita in un intero e quindi ridotta modulo q, producendo la prima metà della firma:
r = 0x113A63990598A3828C407C0F4D2438D990DF99A7F
che utilizziamo, insieme a x (la chiave privata), k (che abbiamo calcolato sopra), e h = bits2int(h1), per calcolare la seconda metà della firma:
s = 0x1313A2E03F5412DDB296A22E2C455335545672D9F
Una firma ECDSA è una coppia di interi. In molti protocolli che richiedono che una firma sia una sequenza di bit (o ottetti), è consuetudine codificare la firma come una SEQUENCE ASN.1 di due valori INTEGER, con regole DER. Questo risulta nella seguente firma di 48 ottetti:
30 2E 02 15 01 13 A6 39 90 59 8A 38 28 C4 07 C0
F4 D2 43 8D 99 0D F9 9A 7F 02 15 01 31 3A 2E 03
F5 41 2D DB 29 6A 22 E2 C4 55 33 55 45 67 2D 9F