ECDSA: Perché le chiavi pubbliche ssh-keygen e Java hanno dimensioni diverse?

4

Sto usando ssh-keygen -t ecdsa -b 256 che genera questo per la parte pubblica:

ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNaHgNjXShzF/hmZOuhTCCsokgpSCyFohETHT4+OQMxW5g+d9nZCYxpDhwivuWbsoXTYpQWlLATXxjbQr2Y3KRY= t0132456@L541918

Ho bisogno di fare lo stesso in Java. Sto usando BouncyCastle:

ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
g.initialize(ecSpec, new SecureRandom());
KeyPair pair = g.generateKeyPair();

ECPublicKey publicKey = (ECPublicKey)pair.getPublic();
System.out.println("kpub=" + Base64.toBase64String(publicKey.getEncoded()));

ma la chiave pubblica è più piccola e non inizia con la stessa intestazione:

kpub=MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvHW0nR1hAzy3BuQR8mMkHqgGvvdXLZWAXS29fkFbhshr8y6xybHh0LRDoaUciYgr3w7WGKpfxFSSFqSjdG8bww==

Come si genera allo stesso modo di ssh-genkey ma in Java?

    
posta akira2x3x 13.07.2016 - 02:18
fonte

1 risposta

10

Le dimensioni sono diverse perché i formati sono diversi. Le stringhe che mostri sono entrambi valori binari codificati in Base64 . In tutto questo messaggio parlo dei valori binari, cioè suppongo che tu abbia prima decodificato le stringhe Base64 in binario.

Matematicamente, una chiave pubblica ECDSA è un punto su una curva ellittica. Un punto ha due coordinate, chiamate X e Y , che sono legate l'una all'altra attraverso l'equazione della curva (in tal caso, Y 2 = X 3 + aX + b per due costanti a e b che definiscono la curva specifica). Qui, si utilizza la curva NIST P-256, che è stata specificata per funzionare in un campo a 256 bit, cioè X e Y sono due interi a 256 bit. Lo standard ANSI X9.62 definisce un formato a 65 byte per rappresentare tale < em> X e Y ; in pratica, un primo byte di valore 0x04, seguito da X su esattamente 32 byte (nella notazione big-endian), quindi Y su altri 32 byte.

Fin qui tutto bene. Quindi sia Java che SSH eseguono il wrap di quel valore a 65 byte in una struttura che identifica anche esplicitamente la curva stessa attraverso alcuni identificatori simbolici. Lo fanno in modo diverso.

Java segue la codifica basata su ASN.1 specificata anche in ANSI X9.62. Esistono diverse opzioni, ma nel tuo caso hai un SEQUENCE il cui contenuto è un sub-% coidato nidificato, quindi un SEQUENCE . Il sub-% co_de nidificato contiene due valori di BIT STRING , il primo è 1.2.840.10045.2.1 (che significa "questa è una chiave pubblica curva ellittica"), e il secondo è 1.2.840.10045.3.1.7, che indica la curva NIST P-256. I contenuti di SEQUENCE sono, esattamente, la codifica di 65 byte del punto di curva. Per farla breve: il valore Java, quando decodificato Base64, fornisce un valore di lunghezza 91 byte, gli ultimi 65 byte di cui la codifica di X e Y .

OpenSSH, d'altra parte, è ben noto per un'allergia cronica agli standard e, naturalmente, ha inventato il proprio formato. È stato quindi documentato in RFC 5656, sezione 3.1 . Fondamentalmente, la chiave codificata consiste in tre "stringhe", una dopo l'altra. Ogni stringa consiste in un'intestazione a 32 bit (4 byte, notazione big-endian) seguita dal valore stringa; l'intestazione contiene la lunghezza del valore, in byte. La prima stringa è la codifica ASCII di "ecdsa-sha2-nistp256" (identifica l'algoritmo della firma). La seconda stringa è la codifica ASCII di "nistp256" (identifica la curva, ridondante con la prima stringa). La terza stringa ha un valore di 65 byte e, avete indovinato, questa è la codifica di 65 byte di X e Y . La lunghezza totale è di 104 byte e la codifica X e Y utilizza gli ultimi 65 di questi 104 byte.

Quindi in pratica, in entrambi i formati, la parte interessante è esattamente gli ultimi 65 byte; il resto è solo un identificatore per la curva coinvolta, in due dialetti distinti. Se generate più chiavi con OBJECT IDENTIFIER , noterete che differiranno solo negli ultimi 65 byte (anche in questo caso, dopo decodifica Base64). Allo stesso modo con la produzione di molte chiavi in Java.

Pertanto, la conversione da una chiave pubblica prodotta da Java a una chiave pubblica compatibile con SSH è tanto semplice quanto prendere gli ultimi 65 byte di quella chiave (dopo la decodifica Base64, dove applicabile) e concatenarli dopo l'intestazione da 39 byte di una chiave SSH.

    
risposta data 13.07.2016 - 03:09
fonte

Leggi altre domande sui tag