Alkampfer's Place

Il blog di Gian Maria Ricci
posts - 659, comments - 871, trackbacks - 80

My Links

News

Gian Maria Ricci Mvp Logo CCSVI in Multiple Sclerosis

English Blog

Tag Cloud

Article Categories

Archives

Post Categories

Image Galleries

I miei siti

Siti utili

Controllare prima di fare :D

La morale di questa storia è, prima di fare qualche cosa controllare se qualcuno la ha già fatta che si risparmia tempo. Due gg fa mi sono posto un problema molto semplice, cifrare da Javascrip in RSA per una pagina ASP.NET, la fregatura è stata che una ricerca mi ha subito dato questo link, da cui ho estratto le routine RSA in javascript, ma che purtroppo non funzionano con quelle di .NET. Dato che RSA è standard, evidentemente la routine in javascript non era stata implementata bene, per questa ragione sono subito andato a verificare L'RFC2313. Dopo una breve lettura mi sono reso conto che l'implementazione da me scaricata sbagliava nel padding.

Senza entrare in dettaglio nell'algoritmo RSA (Anche perché non sono un crittoanalista :P) quest'ultimo lavora su blocchi di dati di lunghezza prefissata, e se il blocco di byte originale non è lungo abbastanza bisogna aggiungere byte di padding affinché il blocco abbia la lunghezza prevista. L'implementazione di cui ho fornito il link sopra fa un padding con zeri, ma non è cosi che dice l'RFC 2313, per cui mi sono messo all'opera.

Il punto 8.1 dice che l'encription Block (EB) deve essere cosi composto 00 || BT || PS || 00 || D dove D sono i dati da cifrare, BT nel caso di una cifratura a chiave pubblica deve valere 02, mentre PS è il blocco di padding che deve contenere byte random differenti da zero. Nel punto 8.2 si cita invece:

In other words, the first octet of EB has the most significance in the integer and the last octet of EB has the least significance.

Questo significa che per convenienza quando si fa la sommatoria del blocco è necessario partire dalla fine di EB, allora tanto vale crearmi l'array direttamente con i byte invertiti. A questo punto si prende l'algoritmo originario e si fanno le modifiche necessarie. Primo passo si deve modificare il costruttore della chiave per calcolare il reale valore di chunkSize ovvero la grandezza massima del blocco di dati originario che entra in un Encryption Block, nella versione originale questo valore è 2 * biHighIndex(this.m); dove biHighIndex mi da l'indice del byte più grande del modulo, ad esempio 127 in caso di modulo a 128 bit. Il valore 2 serve perché nell'algoritmo RSA ogni digit può contenere due byte dello stream originale, per questa ragione il valore del numero di byte di cui deve essere composto un EB è pari a 2 * biHighIndex(this.m) + 2; Da questo valore bisogna sottrarre la grandezza del padding, dato che il PS deve essere minimo 8 byte abbiamo che dal valore precedente è necessario sottrarre 11. Armati di questo valore (chiamato chunkSize) ecco come modificare la funzione di cifratura.

    1     1 function encryptedString(key, s)
    2 {
    3    var a = new Array();
    4    var sl = s.length;
    5    var i = 0;
    6    while (i < sl) {
    7       a[i] = s.charCodeAt(i);
    8       i++;
    9    }
   10    var al = a.length;
   11    var result = "";
   12    var j, k, block;
   13    modLenInOctet = 2 * biHighIndex(key.m) + 2;
   14    for (i = 0; i < al; i += key.chunkSize) {
   15       block = new BigInt();
   16       j = 0;
   17 
   18       //How many char I still had to process?
   19       var BlockLength = (i + key.chunkSize) > al ? al % key.chunkSize : key.chunkSize;
   20       //Create the real block to cyper
   21       var RealBlockToCyper = new Array();
   22       for (copyindex = 0; copyindex < BlockLength; ++copyindex) {
   23          RealBlockToCyper[copyindex] = a[i + BlockLength - 1 - copyindex];
   24       }
   25       //Now create the padding.
   26       RealBlockToCyper[BlockLength] = 0;
   27       var PaddingLength = modLenInOctet - 3 - BlockLength;
   28       for (padindex = 0; padindex < PaddingLength; ++padindex) {
   29          RealBlockToCyper[BlockLength + padindex + 1] = Math.floor(Math.random() * 254) + 1;
   30       } 
   31       RealBlockToCyper[modLenInOctet - 2] = 2;
   32       RealBlockToCyper[modLenInOctet - 1] = 0;
   33 
   34       for (k = 0; k < modLenInOctet; ++j) {
   35          block.digits[j] = RealBlockToCyper[k++];
   36          block.digits[j] += RealBlockToCyper[k++] << 8;
   37       }
   38 
   39       var crypt = key.barrett.powMod(block, key.e);
   40       var text = key.radix == 16 ? biToHex(crypt) : biToString(crypt, key.radix);
   41       result += text + " ";
   42    }
   43    return result.substring(0, result.length - 1); // Remove last space.
   44 }

Come si può vedere nella riga 19 si calcola il numero di byte dello stream originario che posso inserire nel blocco, il numero massimo è key.chunkSize a meno che lo stream originario non abbia meno caratteri, nel qual caso prendo solamente i rimanenti. Il ciclo successivo copia in un nuovo array i byte dello stream originale in senso inverso, alla fine viene poi creato il blocco 00 BT PS 00 a partire dalla linea 26. Dalla linea 34 il codice è eguale alla funzione originale.

Purtroppo tutto questo bel lavoro è stato un po' inutile, se avessi "googlato" la stringa "javascript asp.net rsa interoperability" avrei trovato un bell'articolo che fa esattamente quello che ho fatto io, per cui avrei risparmiato sicuramente tempo.

Alla fine sono contento lo stesso perché cosi ora ho sicuramente una conoscenza migliore dei meccanismi interni dell'RSA.

 

Alk.

Print | posted on mercoledì 24 ottobre 2007 11:13 | Filed Under [ Security ]

Feedback

Gravatar

# Controllare prima di fare :D

Se vi interessa cifrare stringhe da Javascript in RSA da passare al codice lato server questo posto potr&#224;
24/10/2007 11:49 | ExternalBlogs
Gravatar

# Login sicura

In un precedente post ho parlato di come cifrare una stringa in javascript con RSA ora &#232; arrivato il
27/10/2007 12:25 | ExternalBlogs
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET