<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Paolo Ardoino - ideas, programming, web and more... &#187; Italian</title>
	<atom:link href="http://ardoino.com/category/italian/feed/" rel="self" type="application/rss+xml" />
	<link>http://ardoino.com</link>
	<description>Homo quisque faber ipse fortunae suae</description>
	<lastBuildDate>Tue, 27 Oct 2009 22:42:36 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Basic mathematical background and Lenstra factoring algorithm</title>
		<link>http://ardoino.com/22-maths-factoring-lenstra/</link>
		<comments>http://ardoino.com/22-maths-factoring-lenstra/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 07:00:47 +0000</pubDate>
		<dc:creator>Paolo Ardoino</dc:creator>
				<category><![CDATA[Crypto/Security]]></category>
		<category><![CDATA[Italian]]></category>
		<category><![CDATA[Maths]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[factoring]]></category>
		<category><![CDATA[gmp]]></category>
		<category><![CDATA[lenstra]]></category>
		<category><![CDATA[method]]></category>
		<category><![CDATA[rsa]]></category>

		<guid isPermaLink="false">http://ardoino.com/22-maths-factoring-lenstra/</guid>
		<description><![CDATA[

[This article appeared on OndaQuadra0A Elettronic Magazine]
Fondamenti di Matematica - Algoritmi Fondamentali
Metodo delle curve ellittiche per la fattorizzazione
di numeri interi.
by Paolo Ardoino AKA binduck &#60; paolo.ardoino@gmail.com &#62;
&#60; http://ardoino.com &#62;

Prima di passare al prossimo algoritmo per la riduzione in fattori
primi di un numero, conviene spiegare alcuni concetti matematici
e alcuni algoritmi che stanno alla base delle operazioni [...]]]></description>
			<content:encoded><![CDATA[<pre>

[This article appeared on OndaQuadra0A Elettronic Magazine]
Fondamenti di Matematica - Algoritmi Fondamentali
Metodo delle curve ellittiche per la fattorizzazione
di numeri interi.
by Paolo Ardoino AKA binduck &lt; paolo.ardoino@gmail.com &gt;
&lt; http://ardoino.com &gt;

Prima di passare al prossimo algoritmo per la riduzione in fattori
primi di un numero, conviene spiegare alcuni concetti matematici
e alcuni algoritmi che stanno alla base delle operazioni tra numeri
interi composti da molte cifre.
N.B. Questi sono solo riassunti basilari e molto semplici, che potete
consultare per avere un idea delle nozioni che sono richieste negli
articoli matematico-informatici. Per una completa visione di questi
leggete testi di matematica e algoritmi.
Mi raccomando ricordate che la matematica e' molto importante se
volete tuffarvi nel campo della crittografia.
Le implementazioni degli algoritmi presentati in questo articolo
possono essere facilmente trovate in ogni libreria matematica per
qualsiasi linguaggio di programmazione.

0] Notazione usata

1] Concetti fondamentali

1.1] Matematica
1.1.1] Strutture algebriche
1.1.2] Gruppo
1.1.3] Anello
1.1.4] Campo
1.1.5] Aritmetica modulare
1.1.6] Piccolo teorema di Fermat

1.2] Informatica
1.2.1] Calcolabilita' e complessita' di un algoritmo
1.2.2] Rappresentazione numerica di un messaggio
1.2.3] Rappresentazione di un messaggio in Zn

2] Algoritmi fondamentali
2.1] Test di primalita' e teorema di Fermat
2.1.1] Probabilistic primality test
2.2] Numeri random
2.2.1] Linear congruential method
2.3] Massimo comun divisore GCD

3] Elliptic Curve Method
<span id="more-22"></span>

0]
+ Somma
- Sottrazione
/ Divisione
* Moltiplicazione
^ Elevamento a potenza
% Resto della divisione
mod Modulo
= Assegnamento
== Uguaglianza
&gt; Maggiore
&lt; Minore
&gt;= Maggiore uguale

&lt;= Minore uguale
/= Diverso
|x| Valore assoluto di x
° Operatore di composizione
[A1..Ax] Elementi da 1 a x
=&gt; Allora
&lt;=&gt; Se e solo se
@ Per ogni
E Appartenenza
t.c. Tale che
-] Esiste
idA Identitita' in A
log(n) Logaritmo in base due di n
Log(n) Logaritmo in base dieci di n
lim(x -&gt; +inf) f(x)
  si legge: limite per x che tende a piu' infinito di f(x)
GCD(a, b) Massimo comun divisore tra a e b
LCM(a, b) Minimo comune multiplo tra a e b

1] Concetti fondamentali
In questa sezione verranno spiegati in modo molto basilare alcuni
concetti matematici necessari.

1.1.1] Strutture algebriche
Dato un insieme A una operazione binaria interna e' una legge che ad ogni
coppia del prodotto cartesiano AxA fa corrispondere univocamente un
elemento di A.

1.1.2] Gruppi
Un gruppo (G, *) ha un'operazione interna * ed e' un insieme che
soddisfa le proprieta':
-proprieta' associativa P @ a,b,c E G, (a*b)*c == a * (b * c)
-ha l'elemento neutro @ a E G, uG * a == a * uG == a [dove uG e'
l'elemento neutro]
-ha l'inverso @ a E G, -] b E G t.c. a * b == b * a = uG

Dato un gruppo (G, *) se a * b == b * a , @ a, b E G allora G e' un
gruppo commutativo o gruppo abeliano.

1.1.3] Anelli
Un anello (A, +, *) ha due operazioni interne una denotata additivamente
e l'altra moltiplicativamente; gli anelli sono:
-un gruppo abeliano rispetto alla somma [prima operazione]
-il prodotto [seconda operazione] gode della proprieta' associativa
-proprieta' distributiva a * (b + c) == a * b + a * c ,
(a + b) * c == a * c + b * c

Un anello si dice commutativo se il prodotto [seconda operazione] gode
della proprieta' commutativa. Se esiste un elemento neutro rispetto al
prodotto allora l'anello ha un'identita'.

1.1.4] Campi
Un campo (C, +, *) ha due operazione interne, come nel caso dell'anello
una denotata additivamente e una denotata moltiplicamente.
-C e' un gruppo moltiplicativo.
-la seconda operazione e' distributiva rispetto alla prima.

1.1.5] Artimetica modulare
L'aritmetica modulare studia i resti delle divisioni aritmetiche.
X e' il divisendo, m e' il divisore, Q e' il quoziente e R e' il resto.
(X mod m) = R si legge X modulo m e' uguale a R.
Esempi:
5 mod 3 = 2 infatti m * Q + R == X -&gt; 3 * 1 + 2 == 5
31 mod 43 = 31 infatti 43 * 0 + 31 == 31

Possiamo dire che R &lt; m, infatti 0 &lt; R &lt; m - 1

(X mod 1) == 0 -&gt; un qualsiasi numero modulo 1 e' sempre uguale a 0.
(0 mod m) == 0 -&gt; 0 modulo qualsiasi numero e' sempre uguale a 0.
(X + Y) (mod m) == X(mod m) + Y(mod m) -&gt; il resto di una somma e'
uguale alla somma dei resti.
(X * Y) (mod m) == X(mod m) * Y(mod m) -&gt; il resto di un prodotto e'
uguale al prodotto dei resti. Quest'ultima equivalenza ci sara' utile
nella determinazione dei resti in divisioni tra numeri composti da
molte cifre poiche' ci dice che:
(X^2)(mod m) == X(mod m) * X(mod m) == R^2

1.1.6] Piccolo teorema di Fermat
Cosa ci dice il piccolo teorema di Fermat?
p divide a^(p - 1) - 1, quando p e' primo e a e' primo con p [non hanno
divisori comuni].
Una generalizzazione che puo' seguire da questa forma e': presi due
numeri interi positivi m, n con m == n allora a^n == a^m (mod p).
[Utilizzato per la dimostrazione dell'algoritmo RSA].

1.2] Informatica

1.2.1] Calcolabilita' e complessita' di un algoritmo
Calcolabilita': e' possibile scrivere un algoritmo per risolvere il
problema?

Complessita': sapendo che il problema e' calcolabile, quanto e'
complesso? Per valutare la complessita' ci interessiamo del tempo
di calcolo (tralaciamo quindi lo spazio di memoria occupato).
La complessita' viene calcolata tenendo conto di tutte le operazioni
algebriche e logiche, accesso in lettura e scrittura, etc...
Nelle nostre valutazioni, comunque, partiremo dal presupposto che la
macchina che eseguira' l'algoritmo sara' una macchina ideale, un
calcolatore astratto che non tenga conto delle prestazioni hardware.
Per poter descrivere la complessita' di un algoritmo e' necessario
conoscere gli ordini di grandezza: teta, omega, O.
Prendiamo ora due funzioni f e g, diremo che:
f e' O(g) se f cresce al piu' come g, quindi g e' il limite superiore.
f e' omega(g) se f cresce almeno come g, quindi g e' il limite
inferiore.
f e' teta(g) se f cresce come g, quindi f ha lo stesso ordine di
grandezza di g.
Per il concetto di limite, lim (x -&gt; +inf) f(x)/g(x) == c
Se c /= 0 =&gt; f e' teta(g) e quindi g e' teta(f)
Se c == 0 =&gt; f e' O(g)
Un esempio potrebbe essere: questo algoritmo ha complessita' O(log n),
questo vuol dire che ha complessita' log in base 2 di n.

Negli algoritmi ci puo' essere un'istruzione dominante allora accade che
riducendo la complessita' di questa, la complessita' dell'intero
algoritmo cali vertiginosamente.

Il metodo migliore per valutare la complessita' di un codice e' quello
di spezzarlo in blocchi e analizzare l'ordine di grandezza di ogni
singolo blocco.

Esempio di calcolo della complessita':
{
int n, i, p;
scanf("%d", &amp;n);
for(i = 0, p = 0; i &lt; n; i++) { p++; }
}
La complessita' di questo blocco e' O(n). Questa potrebbe crescere
inserendo una nuova operazione di complessita' maggiore.

1.2.2] Rappresentazione numerica di un messaggio
N.B QUESTO PARAGRAFO E QUELLO SULLA RAPPRESENTAZIONE DEI NUMERI IN Zn
sono fondamentali per la comprensione della maggior parte degli
algoritmi di crittografia.

Supponiamo per esempio che un messaggio sia composto solo dalle 21
lettere dell'alfabeto italiano piu' lo spazio. Quindi con i numeri
compresi tra 0 e 21 possiamo indicare ogni carattere.
Dati m blocchi, quanti blocchi possiamo codificare col nostro
insieme di 22 caratteri? 22^m; quindi possiamo indicare ogni blocco
identificandolo tra 0 e (22^m) - 1.
Prendiamo per esempio un blocco [A1..Am], indichiamo con i numeri
[X1..Xm] corrispondenti alle lettere A1..Am e indichiamo il blocco
col numero risultante.
Piu' precisamente con il metodo illustrato qui sotto otteniamo che ogni
blocco sia indicato univocamente:
x = 22^(m - 1) * X1 + 22^(m - 2) * X2 + ... + 22^1 * X(m - 1) + Xm
Il processo e' ovviamente invertibile, infatti possiamo ricavare
[X1..Xm] e quindi [A1..Am]. Prendiamo il nostro x e dividiamolo per 22,
il resto ottenuto da questa divisione sara' Xm. Ora dividiamo il
quoziente (Q) della divisione per 22 e otteniamo X(m - 1) e cosi' via.

1.2.3] Rappresentazione di un messaggio in Zn
N.B QUESTO PARAGRAFO E' FONDAMENTALE PER LA COMPRENSIONE DELLA
MAGGIOR PARTE DEGLI ALGORITMI DI CRITTOGRAFIA.
[Questo paragrafo e' in parte un riassunto, semplificato della Ref.2]
[In questo paragrafo e' necessaria la parte di aritmetica modulare]
Una volta trovato il numero di simboli del nostro alfabeto (22 nel
paragrafo precente), genericamente n, possiamo indicare con Zn
l'insieme dei numeri compresi tra 0 e n - 1. Di qui possiamo arrivare
a scrivere una funzione f:Zn -&gt; Zn che ad ogni blocco di m caratteri di
Zn associa un nuovo blocco in Zn; questo procedimento rende possibile
l'operazione inversa (descrittazione) f^-1.
Una condizione necessaria su f perche' questa sia invertibile e' che
sia iniettiva, cioe' che a ogni elemento del dominio ne associ uno e
uno solo dell'immagine; se la condizione non fosse necessaria allora
non potremmo scrivere una funzione che decritta univocamente i blocchi
crittati.
Matematicamente una funzione si dice iniettiva se:
f(x) == f(x') &lt;=&gt; x == x'

Una funzione f e' invertibile se e solo se e' iniettiva.

La condizione di invertibilita' si esprime in questo modo:
Presi due elementi x E X, y E Y sia f una funzione da X a Y,
allora esiste una funzione f^-1 da Y a X se e solo se
f^-1(f(x)) = x  e f(f^-1(y)) = y
L'invertibilita' puo' essere scritta anche cosi':
g ° f = idA e f ° g = idB
[In generale: f ° g == f(g)]

**EQUIVALENZA**
Definiamo ora l'operatore di equivalenza o conguenza in Zn
a == b (mod n).
Detto piu' semplicemente se pensiamo a Zn come ad un insieme di
numeri consecutivi, prendiamo due numeri a, b E Zn.
**SOMMA**
Se a + b &lt; n allora possiamo prendere come risultato della somma
a + b.
Se a + b &gt;= n allora dobbiamo sottrarre n poiche' sforeremo
dall'insieme Zn dato che dovremmo considerare numeri piu' grandi di n
che non possono essere dentro l'insieme.
Quindi se ripensiamo all'equivalenza un n + 1 == 1 in Zn, n + 2 == 2
in Zn, etc...
L'operazione di riduzione si effettua per passare da un generico numero
al suo corrispondente in Zn.
Esempio:
3 + 5 == 2 in Z6, poiche' 8 (mod 6) == 2
**PRODOTTO**
Ovviamente tutto cio' che abbiamo detto finora per la somma vale allo
stesso modo per il prodotto.
a * b = c (mod n)
**OPPOSTO**
Ogni x E Zn ammette opposto, che e' semplicemente il numero congruente
a -x in Zn cosicche' x + (-x) == 0, poiche' 0 e' l'elemento neutro della
somma.
Esempio:
In Z8, l'inverso di 5 e' 3, infatti 5 + 3 == 8 == 0
**INVERSO**
Per quanto riguarda l'inverso dobbiamo riferirci all'elemento neutro del
prodotto che e' 1, infatti x * x^-1 == 1.
Non tutti gli elementi di Zn quindi ammettono inverso. Prendiamo ad
esempio in Z5 il numero 2; bene il suo inverso sara' 3, poiche'
2 * 3 == 6 == 1.
Mentre 2 non ha inverso in Z6, dato che ogni numero moltiplicato per 2
da' come risultato un numero pari, mentre l'inverso dovrebbe essere
dispari.
In generale possiamo riassumere che un numero ha inverso in Zn se e solo
se GCD(x, n) == 1.
Di conseguenza se n e' primo (cioe' divisibile solo per uno e per se
stesso) allora ogni numero tranne 0 ammette inverso, e Zn definito
queste operazioni di somma e prodotto e' un campo; al contrario se
n non e' primo esiste almeno un numero in Zn che non ha inverso e
Zn e' un anello.

2] Algoritmi fondamentali
Quali caratteristiche deve avere un algoritmo?
a) Finito: deve terminare dopo un numero finito di passi.
b) Definito: essendo i computer delle macchine deterministiche, ogni
passo dell'algoritmo deve essere definito precisamente.
c) Input: 0 o piu' valori in input.
d) Output: 1 o piu' output.
e) Realizzabilita': tutte le operazioni usate nell'algoritmo devono
poter essere fattibili anche da un uomo su carta.

Un algoritmo si dice computazionalmente trattabile se esiste un
algoritmo efficiente che lo risolva.
Un algoritmo si dice efficiente se esiste una funzione che lo limita
superiormente.

2.1] Test di primalita' e teorema di Fermat
Secondo quanto ci dice il teorema di Fermat x^(p-1) mod p == 1
se p e' primo e x non e' multiplo di p; quando questa relazione non e'
verificata allora p e' composto.
Servono quindi solo O(log n) moltiplicazioni mod n per verificare il
teorema di Fermat. Comunque per n molto grandi i calcoli diventano
molto costosi in termini di tempo e risorse.

2.1.1] Test probailistico di primalita'
Il test probabilistico di primalita' in p e' fondamentale per
controllare in modo veloce, e comunque affidabile, se un intero e'
primo oppure composto (e quindi riducibile in fattori primi :)).
0] Prendiamo un numero intero n dispari
(ovviamente se e' pari avra' almeno un fattore, 2);
1] Sia n = 1 + (2^k) * q
(q sara' dispari)
2] Scegliamo un x casuale tale che 1 &lt; x &lt; n
3] Sia j = 0 e y = (x^q) mod n
(questo calcolo richiede O(log q) passi)
4] Se j == 0 e y == 1, oppure y == n - 1 allora n e' probabilemte primo
Se j &gt; 0 and y == 1 saltiamo al passo 6.
Altrimenti proseguiamo.
5] j = j + 1
Se j &lt; k allora y = (y^2) mod n e ritorniamo al passo 4.
Altrimenti proseguiamo.
6] n e' sicuramente composto.

L'algoritmo in se, computato una singola volta ha una probabilita' pari
a 1/4 di fallire; per ottenere una maggiore sicurezza e' possibile
ripetere l'algoritmo r volte, cosi' che la probabilita' di fallimento
sia di (1/4)^r. Pensiamo quindi di ripetere l'algoritmo un numero
finito di volte, ad esempio 100, la probabilita' che il nostro
algoritmo fallisca sara' di (1/4)^100, praticamente 0.

[Questo test e' il piu' gettonato ed e' implementato in tutte le
librerie matematiche (vedi ad esempio GNU Multi Precision e la libreria
matematica di OpenSSL) per il fatto che e' veloce ed affidabile.]

2.2] Numeri random
Un numero random, e' un numero scelto a caso; scrivere un algoritmo
che fornisca una buona fonte di numeri primi non e' affatto semplice.
Algoritmi come il supe-rrandom number generator sono obsoleti e
convergono in modo molto veloce e questo ci insegna che per generare
numeri random non si dovrebbe usare metodi casuali, ma invece bisogna
basarsi sulla teoria matematica.
Una fonte di numeri casuali nei sistemi GNU/Linux e' /dev/random.
In C possiamo per ottenere numeri random e' sufficiente appoggiarsi
a due funzioni contenute nella stdlib, che sono la srand(), che permette
di settare il random seed e la rand() che ci restituisce un intero
casuale compreso tra 0 e RAND_MAX.
#define    RAND_MAX        2147483647
Ovviamente la sequenza di numeri casuali e' riottenibile reinserendo
il lo stesso seed in srand().
Un esempio di inizializzazione potrebbe essere srand(time(NULL));.

2.2.1] Linear congruential method
Per generare numeri casuali uniformemente distribuiti tra 0 e 1 si
utilizza prevaletentemente il linear conguential method.
In questo documento mostro solo l'idea alla base dell'algoritmo.
Si scelgano 4 numeri:
m modulo t.c m &gt; 0
a moltiplicatore t.c 0 &lt;= a &lt; m
c incrementatore t.c 0 &lt;= c &lt; m
Xo valore di partenza t.c 0 &lt;= Xo &lt; m

La sequenza di numeri casuali Xn seguira da:
X(n + 1) = (a*Xn + c) mod m
(n &gt;= 0)
Ovviamente per scegliere i 4 numeri di partenza ci son dei metodi che
ci permettono di scegliere dei buoni valori.

2.3] Massimo comun divisore GCD
[GCD == Great Commin Divisor]
In questa sezione vedremo oltre l'aspetto matematico del massimo comun
divisore anche l'algoritmo per il calcolo.
Dati due numeri a, b il massimo comun divisore GCD(a, b) e' numero piu'
grande che li divide entrambe. Vediamo ora alcune proprieta' del GCD.
GCD(0, 0) == 0
GCD(u, v) == GCD(v, u)
GCD(u, v) == GCD(-u, v)
GCD(u, 0) == |u|

L'algoritmo di Euclide ci permette di trovare il massimo comun divisore
senza prima trovare i fattori primi di u e v.
Poniamo sempre a sinistra l'intero maggiore.

Vediamo prima l'algoritmo originale:
0] Siano A e C due interi &gt; 1 calcolarne il GCD
1] Se A &gt; C e C divide A =&gt; C e' il GCD(A, C)
2] (A mod C) == 1 allora A e C son primi tra loro, quindi
   l'algoritmo termina. Altrimenti (A mod C) &gt; 1, calcoliamo il
   GCD(C, A mod C).
Questo algoritmo da vita quindi a una procedura ricorsiva.

Ora invece vediamo un'implementazione moderna dell'algoritmo.
0] Siano u e v due interi &gt;= 0 calcolare GCD(u, v)
1] Se v == 0 allora GCD(u, v) == u
2] r = u mod v, u = v, v = r; ritorniamo al punto 1].

Esistono altri algoritmi per il calcolo del GCD [come il binary gcd
algorithm], e quindi si potrebbe continuare a parlare del massimo
comun divisore per pagine e pagine, ma direi che per rendere l'idea
i due descritti son piu' che sufficienti.

3] Elliptic Curve Method

L'idea che sta alla base dell'algoritmo di Lenstra e' quella di
sfruttare delle curve ellittiche, scelte casualmente, per svolgere
dei tentativi di fattorizzazione, e ognuno di questi ha una probabilita'
non nulla di trovare un fattore primo di N.
Inanzitutto vediamo come e' fatta una curva ellittica, la cui equazione
e': y^2 = x^3 + a*x + b
Da questo possiamo dedurre che una curve ellittica e' un grafico di
una cubica (terzo grado) [non bisogna confondersi con l'ellisse].
Le curve ellittiche son funzioni continue il che ci permette di
costruire operazioni binarie tra i suoi vari punti in un modello
geometrico naturale, il che trasforma l'insieme di punti in gruppo
abeliano.
Le CE possono essere definite su qualsiasi campo k.
L'algoritmo e' un miglioramento dell'algoritmo Pollard p-1 ed era il
metodo piu' veloce per trovare i fattori primi di un intero prima
del Generalized Number Field Sieve. Comunque e' ancora l'algoritmo
piu' veloce per interi inferiore a 64 bits [20 cifre].
Il miglioramento consiste nel fatto che l'algoritmo di Lenstra
considera il gruppo di una curva ellittica casuale su un campo finito
Zp [con p primo], il quale ha sempre ordine p - 1. Invece l'ordine
del gruppo della CE su Zp varia casualmente tra  p e 2p.

0]
Sia n il nostro intero da ridurre in fattori primi.

1]
Scegliamo una curva ellittica C: y^2 = x^3 + a*x + b, tale che a e b
appartengano a Z (insieme dei numeri interi).
Scegliamo poi un punto P(x, y).
Sia la scelta di C che la scelta di P dovranno essere pseudo-casuali.
[Se noi fallissimo il tentativo di fattorizzazione con la coppia (C,P)
scelta ora dovremmo sceglierne un'altra a caso.]

2]
Verifichiamo ora che il massimo comun divisore GCD(4a^3 + 27b^2, n) == 1
Se questa condizione e' vera abbiamo la conferma che la curve da noi
scelta e' riducibile mod p. Questo vuol dire che, preso un primo p,
possiamo considerare i coefficienti dell'equazione della curva modulo p
se e solo se questi sono primi con p.
[GCD(K,Z) leggasi massimo comun divisore tra K e Z]
Se 1 &lt; GCD(4a^3 + 27b^2, n) &lt; n allora abbiamo trovato un divisore non
banale di n, quindi abbiamo trovato un fattore primo di n. Ogni volta
che si verifica questa condizione possiamo dividere n per il fattore
trovato e continuare la scomposizione in fattori primi.
Se, invece, troviamo che il risultato del massimo comun divisore e'
uguale ad n allora dobbiamo generare una nuova coppia (C,P).

3]
Prendiamo un intero k tale che questo sia il prodotto di tutti i
numeri primi minori di un certo b scelto a caso.
Assumiamo per facilitare le operazioni di calcolo che b sia inferiore
a un intero a 4 byte senza segno.
Ora e' sufficiente trovare tutti i primi inferiori di questo b e
moltiplicarli, cosicche' k sia multiplo di ognuno di loro.
Si calcoli kP nel gruppo, con il metodo delle potenze veloci, modulo n.
kP e' uno zero della curva ellittica nel gruppo Zp [dove p e' un
divisore primo di n], ma non e' uno zero nel gruppo Zq [dove q e' un
altro divisore di n, con q /= p]. A questo punto possiamo trovare un
fattore di n computando il GCD(xP, n) [dove xP e' la prima coordinata
del punto P].

4] Se il procedimento fallisce e' necessario ripartire con una nuova
coppia (C, P).

Un'implementazione decente dell'algoritmo e' gmp-ecm di Paul Zimmermann
and Alexander Kruppa.
[Il codice dell'SECMI (Simple Elliptic Curve Method Implementation) che
trovate sul mio sito e' una semplice reimplementazione di quello scritto
da Rihard Brent, che dava dei problemi con alcuni numeri e poteva essere
velocizzato].

Per qualsiasi chiarimento scrivetemi a paolo.ardoino@gmail.com
Ciao

Riferimenti:
*1 - The art of computer programming Vol. 1 - 2
*2 - Appunti di crittografia di Giovanni Alberti
*3 - Libri e appunti vari di matematica</pre>
]]></content:encoded>
			<wfw:commentRss>http://ardoino.com/22-maths-factoring-lenstra/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>DES, Blowfish, IDEA, MD5: implemtentation ( for Ondaquadra E-zine )</title>
		<link>http://ardoino.com/21-openssl-des-blowfish-idea-md5-implementation/</link>
		<comments>http://ardoino.com/21-openssl-des-blowfish-idea-md5-implementation/#comments</comments>
		<pubDate>Wed, 20 Feb 2008 07:00:59 +0000</pubDate>
		<dc:creator>Paolo Ardoino</dc:creator>
				<category><![CDATA[Crypto/Security]]></category>
		<category><![CDATA[Italian]]></category>
		<category><![CDATA[blowfish]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[cryptography]]></category>
		<category><![CDATA[des]]></category>
		<category><![CDATA[idea]]></category>
		<category><![CDATA[Maths]]></category>
		<category><![CDATA[md5]]></category>
		<category><![CDATA[openssl]]></category>
		<category><![CDATA[rsa]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://ardoino.com/21-openssl-des-blowfish-idea-md5-implementation/</guid>
		<description><![CDATA[
[This article appeared on OndaQuadra0B Elettronic Magazine - Mar 2004 ]
OpenSSL/DES,OpenSSL/Blowfish,OpenSSL/IDEA,OpenSSL/MD5: implemtentation
UNISFED written and coded by Paolo Ardoino &#60;paolo.ardoino@gmail.com&#62;

0. Intro
1. Descrizione algoritmi
2. Funzioni &#38; headers DES
3. Funzioni &#38; headers Blowfish
4. Funzioni &#38; headers IDEA
5. Funzioni &#38; headers MD5

In questo articolo vedremo come implementare quattro tra gli algoritmi
piu' famosi e piu' usati nel campo della crittografia:
DES,Blowfish,IDEA,MD5

1. [...]]]></description>
			<content:encoded><![CDATA[<pre id="line12">
[This article appeared on OndaQuadra0B Elettronic Magazine - Mar 2004 ]
OpenSSL/DES,OpenSSL/Blowfish,OpenSSL/IDEA,OpenSSL/MD5: implemtentation
UNISFED written and coded by Paolo Ardoino &lt;<span class="start-tag">paolo.ardoino@gmail.com</span>&gt;

0. Intro
1. Descrizione algoritmi
2. Funzioni &amp; headers DES
3. Funzioni &amp; headers Blowfish
4. Funzioni &amp; headers IDEA
5. Funzioni &amp; headers MD5

In questo articolo vedremo come implementare quattro tra gli algoritmi
piu' famosi e piu' usati nel campo della crittografia:
DES,Blowfish,IDEA,MD5
<span id="more-21"></span>
1. Descrizione algoritmi

DES[Data Encryption Standard]:
Il DES fu sviluppato dall'IBM nel 1970, divento' standard nel 1976
e fu adottato dal governo statunitense nel 1977 ed e' stato utilizzato
per lungo tempo dal governo e da aziende private.
Il DES e' un block cipher (cifrario a blocchi) che lavora con blocchi
di 64 bits (8 bytes), utilizzando chiavi a 56 bits.
Su ogni blocco vengono effettuate delle permutazioni oltre che 16
cicli di xor e permutazioni.
Nel 1998 e' stata dimostrata la vulnerabilita' di questo algoritmo,
da parte dell' EFF, utilizzando un attacco di tipo brute force.
Per ovviare a questo problema e' stato introdotto il 3DES, che e'
basato su una ripetizione del cifrario DES, utilizzando chiavi a 112
bits.

Blowfish:
Nel 1993 Bruce Schneier sviluupo l'algoritmo conosciuto come Blowfish.
Come il DES opera su blocchi di 64 bits. Blowfish puo' operare con
chiavi fino a 448 bits, anche se tipicamente si utilizzano chiavi
a 128 bits. L'utilizzo di Blowfish presenta molti vantaggi a partire
dalla sua velocita' e compattezza fino ad arrivare alla sicurezza
infatti non si conoscono attacchi efficaci, inoltre e' un algoritmo
non patentato.

IDEA[International Data Encryption Algorithm]:
L'algoritmo IDEA lavora con chiavi a 16 bytes (128 bits), su blocchi
di 64 bits. E' basato su 8 cicli identici seguiti da una trasformazione
dell'output.

MD5[Message Digest 5]
MD5, creato nel 1991 da Ronald Rivest e' una funzione one-way hashing,
cioe' prende un messaggio e ne deriva una stringa di un 16 bytes
chiamata anche message digest.

2. Funzioni &amp; headers DES
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">des.h</span>&gt;

Poiche' la password e' 64 bits (anche se poi e' ridotta a 56 bits) e
operiamo su blocchi di 8 bytes, quindi dovremmo operare su blocchi di
64 bits. Quindi dichiariamo che sia la password che i messaggi in
chiaro (plaintext) che quelli cifrati (cipher text) dovranno essere
blocchi di 64 bits; per fare questo introduciamo il tipo des_cblock.
Il tipo dello scheduling della password e' des_key_schedule.

Ora possiamo passare alle funzioni:

/* des_read_pw_string(): scrive la string contenuta in prompt,
leva l'echo sulla stdin e legge la password in input. La password
viene inserita in buf ed e' al massimo lenght caratteri. Se verfify
e' posto a 1 chiede la riconferma della password. */
int des_read_pw_string(char *buf, int lenght, const char *prompt,
int verify);

/* des_string_to_key(): converte la stringa contenuta in str in una
chiave DES a 64 bits */
void des_string_to_key(const char *str, des_cblock *key);

/* des_set_key_checked(): controlla se la chiave passata e' dispari
e imposta loschedule della chiave */
int des_set_key_checked(const_des_cblock *key,
des_key_schedule schedule);

/* des_ecb_encrypt(): e' la routine di cifratura base per il DES
offerta dalla libreria. Cifra/Decifra blocchi di 8 bytes a seconda
che mode sia DES_ENCRYPT o DES_DECRYPT. ks e' il key schedule */
void des_ecb_encrypt(const_des_cblock *input, des_cblock *output,
des_key_schedule ks, int enc);

Per informazioni sulle funzioni non illustrate qui: man des

3. Funzioni &amp; headers Blowfish

#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">bf.h</span>&gt;</pre>
<pre id="line104">Per leggere la password da input usiamo la stessa funzione che
utilizziamo per il DES: des_read_pw_string() [leggete la sez. 2].
La chiave dovra' essere di tipo BF_KEY.

/* BF_set_key(): imposta la chiave (di tipo BF_KEY) usando la stringa
data di lunghezza len */
void BF_set_key(BF_KEY *key, int len, const unsigned char *data);

/* BF_ecb_encrypt(): e' la funzione base per cifrare/decifrare
offerta dalla libreria. Cifra/Decifra blocchi di 8 bytes a seconda
che mode sia BF_ENCRYPT o BF_DECRYPT. */
void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
BF_KEY *key, int enc);

4. Funzioni &amp; headers IDEA

#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">idea.h</span>&gt;

Lo schedule della chiave deve essere impostato a IDEA_KEY_SCHEDULE.
Ricordo, inoltre, che il ciphertext e il plaintext devono essere
blocchi di 8 bytes.
Per leggere la password da input usiamo la stessa funzione che
utilizziamo per il DES: des_read_pw_string() [leggete la sez. 2].

/* idea_set_encrypt_key(): imposta il key schedule della chiave
per la fase di cifrazione */
void idea_set_encrypt_key(const unsigned char *key,
IDEA_KEY_SCHEDULE *ks);

/* idea_set_decrypt_key(): imposta il key schedule della chiave
per la fase di decifrazione partendo dal key schedule generato
con idea_set_encrypt_key() */
void idea_set_decrypt_key(IDEA_KEY_SCHEDULE *ek,
IDEA_KEY_SCHEDULE *dk);

/* idea_ecb_encrypt(): cifra/decifra [a seconda del key schedule
passatogli] i dati contenuti nel blocco di 8 bytes in e li mette
nel blocco di 8 bytes out. */
void idea_ecb_encrypt(const unsigned char *in, unsigned char *out,
IDEA_KEY_SCHEDULE *ks);

5. Funzioni &amp; headers MD5

#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">md5.h</span>&gt;

Questa libreria include alcune funzioni per l'hashing dei messaggi.

/* MD5(): performa l'hash del messaggio passatogli */
unsigned char *MD5(const unsigned char *d, unsigned long n,
unsigned char *md);
[Se md e' NULL il message digest viene messo in un array statico]

A livello applicativo, invece di usare questa funzione conviene
utilizzare le routines EVP, che lavorano a piu' alto livello.

#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">evp.h</span>&gt;

/* EVP_md5(): ritorna una struttura EVP_MD per l'algoritmo md5 */
EVP_MD *EVP_md5(void);

/* EVP_DigestInit(): inizializza un context CTX per usare un digest
di tipo type*/
void EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type);

/* EVP_DigestUpdate(): computa l'hash di cnt bytes di d nel CTX */
void EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d,
unsigned int cnt);

/* EVP_DigestFinal(): mette l'hash contenuto nel context CTX
in md*/
void EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md,
unsigned int *s);

man md5

Ora che abbiamo visto le principali funzioni potete guardarvi
il codice sorgente di UNISFED.
[Il codice contiene anche l'algoritmo di crittografia a chiave pubblica
RSA, descritte nel numero 0A di Ondaquadra]

Da compilarsi [una volta suddivisi i files] in questo modo:
gcc unisfed.c -o unisfed -lssl

Ciao a tutti e alla prossima.
-------------------block_ciphers.c-------------------------------------
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">des.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">blowfish.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">idea.h</span>&gt;</pre>
<pre id="line193">#define MAXPASSLEN 31

/* DES
 * If mode = 1 encrypts *filein file with DES algorithm
 * If mode = 0 decrypts *filein file with DES algorithm
 * output is written in *fileout file
 * Returns 1 if the function runs successfully
 * Works on 8 bytes blocks
 *
 */
void des_encrypt_decrypt(int mode, char *filein, char *fileout)
{
	FILE *fpin,*fpout;
	char buf[MAXPASSLEN];
	des_cblock key,inmsg,outmsg; /* key, plaintext, ciphertext must
	be 8 byte blocks */
	des_key_schedule sched;

	if (strcmp(filein,fileout) == 0) {
		fprintf(stderr,"Error: input and output files must not \
		be the same file.\n");
		exit(EXIT_FAILURE);
	}
	/* des_read_pw_string reads password from stdin and stores it
	in buf this function automatically asks to re-enter password
	and checks it */
	memset(buf,'\0',MAXPASSLEN);
	if (mode == 1) {
		printf("Encrypting file '%s' with des cipher.\n", \
		filein);
		if (des_read_pw_string(buf,MAXPASSLEN - 1,"Enter the \
		password:\n",1) != 0) {
			fprintf(stderr,"Error: failed to read \
			password.\n");
			exit(EXIT_FAILURE);
		}
	} else {
		printf("Decrypting file '%s' with des cipher.\n",\
		filein);
		if (des_read_pw_string(buf,MAXPASSLEN - 1,"Enter the \
		password:\n",0) != 0) {
			fprintf(stderr,"Error: failed to read \
			password.\n");
			exit(EXIT_FAILURE);
		}
	}
	/* des_string to key convers the password to a key */
	des_string_to_key(buf,&amp;<span class="entity">key</span>);
	/* des_set_key_checked checks that a key passed in of odd
	parity and set up the key schedule */
	des_set_key_checked(&amp;<span class="entity">key</span>,sched);
	fpin = fopen(filein,"r");
	if ((fpout = fopen(fileout,"w")) == NULL) {
		fprintf(stderr,"Error: failed to open output file.\n");
		exit(EXIT_FAILURE);
	}
	/* reads 8 bytes at a time(block=8bytes),encrypts/decrypts
	each block with ecb */
	while (fread(inmsg,1,8,fpin)) {
		memset(outmsg,'\0',8);
		des_ecb_encrypt(&amp;<span class="entity">inmsg</span>,&amp;<span class="entity">outmsg</span>,sched,mode);
		fwrite(outmsg,1,8,fpout);
		memset(inmsg,'\0',8);
	}
	fclose(fpin);
	fclose(fpout);
	printf("Done.\n");
	return;
}

/* Blowfish
 * If mode = 1 encrypts *filein file with Blowfish algorithm
 * If mode = 0 decrypts *filein file with Blowfish algorithm
 * output is written in *fileout file
 * Returns 1 if the function runs successfully
 * Works on 8 bytes blocks
 *
 */
void bf_encrypt_decrypt(int mode, char *filein, char *fileout)
{
	FILE *fpin,*fpout;
	char buf[MAXPASSLEN];
	unsigned char inmsg[8],outmsg[8]; /* blowfish operates on 8
	byte blocks */
	BF_KEY key;

	if (strcmp(filein,fileout) == 0) {
		fprintf(stderr,"Error: input and output files must \
		not be the same file.\n");
		exit(EXIT_FAILURE);
	}
	/* reads password from stdin using the same function used
	for des passwords */
	memset(buf,'\0',MAXPASSLEN);
	if (mode == 1) {
		printf("Encrypting file '%s' with BlowFish cipher.\n",\
		filein);
		if (des_read_pw_string(buf,MAXPASSLEN - 1,"Enter the \
		password:\n",1) != 0) {
			fprintf(stderr,"Error: failed to read \
			password.\n");
			exit(EXIT_FAILURE);
		}
	} else {
		printf("Decrypting file '%s' with BlowFish cipher.\n",\
		filein);
		if (des_read_pw_string(buf,MAXPASSLEN - 1,"Enter the \
		password:\n",0) != 0) {
			fprintf(stderr,"Error: failed to read \
			password.\n");
			exit(EXIT_FAILURE);
		}
	}
	/* set up the key using password stored in buf from
	des_read_pw_string */
	BF_set_key(&amp;<span class="entity">key</span>,strlen(buf),buf);
	fpin = fopen(filein,"r");
	if ((fpout = fopen(fileout,"w")) == NULL) {
		fprintf(stderr,"Error: failed to open output file.\n");
		exit(EXIT_FAILURE);
	}
	/* reads 8 bytes at a time(block=8bytes),encrypts/decrypts each
	block with ecb */
	while (fread(inmsg,1,8,fpin)) {
		memset(outmsg,'\0',8);
		BF_ecb_encrypt(inmsg,outmsg,&amp;<span class="entity">key</span>,mode);
		fwrite(outmsg,1,8,fpout);
		memset(inmsg,'\0',8);
	}
	fclose(fpin);
	fclose(fpout);
	printf("Done.\n");
	return;
}

/* IDEA
 * If mode = 1 encrypts *filein file with IDEA algorithm
 * If mode = 0 decrypts *filein file with IDEA algorithm
 * output is written in *fileout file
 * Returns 1 if the function runs successfully
 * Works on 8 bytes blocks
 *
 */
void idea_encrypt_decrypt(int mode, char *filein, char *fileout)
{
	FILE *fpin,*fpout;
	char buf[MAXPASSLEN];
	unsigned char inmsg[8],outmsg[8]; /* idea operates on 8
	byte blocks */
	IDEA_KEY_SCHEDULE sched,dc_sched;

	if (strcmp(filein,fileout) == 0) {
		fprintf(stderr,"Error: input and output files must not\
		be the same file.\n");
		exit(EXIT_FAILURE);
	}
	/* reads password from stdin using the same function used for
	des passwords */
	memset(buf,'\0',MAXPASSLEN);
	if (mode == 1) {
		printf("Encrypting file '%s' with IDEA cipher.\n",\
		filein);
		if (des_read_pw_string(buf,MAXPASSLEN - 1,"Enter the \
		password:\n",1) != 0) {
			fprintf(stderr,"Error: failed to read \
			password.\n");
			exit(EXIT_FAILURE);
		}
	} else {
		printf("Decrypting file '%s' with IDEA cipher.\n",\
		filein);
		if (des_read_pw_string(buf,MAXPASSLEN - 1,"Enter the \
		password:\n",0) != 0) {
			fprintf(stderr,"Error: failed to read \
			password.\n");
			exit(EXIT_FAILURE);
		}
	}
	/* set up the key schedule for encryption */
	idea_set_encrypt_key(buf,&amp;<span class="entity">sched</span>);
	/* setting up the key schedule for decryption in mode == 0 */
	if (mode == 0) {
		idea_set_decrypt_key(&amp;<span class="entity">sched</span>,&amp;<span class="entity">dc_sched</span>);
		sched = dc_sched;
	}
	fpin = fopen(filein,"r");
	if ((fpout = fopen(fileout,"w")) == NULL) {
		fprintf(stderr,"Error: failed to open output file.\n");
		exit(EXIT_FAILURE);
	}
	/* reads 8 bytes at a time(block=8bytes),encrypts/decrypts each\
	block with ecb */
	while (fread(inmsg,1,8,fpin)) {
		memset(outmsg,'\0',8);
		idea_ecb_encrypt(inmsg,outmsg,&amp;<span class="entity">sched</span>);
		fwrite(outmsg,1,8,fpout);
		memset(inmsg,'\0',8);
	}
	fclose(fpin);
	fclose(fpout);
	printf("Done.\n");
	return;
}
-------------------end block_ciphers.c---------------------------------

-------------------hash.c----------------------------------------------
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">md5.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">evp.h</span>&gt;

void make_hex(u_char *in, u_char *out)
{
    const char    *hex = "0123456789abcdef";
    int i;

    for(i = 0; i &lt; 16; i++, in++) {
        *out++ = hex[*in &gt;&gt; 4];
        *out++ = hex[*in &amp; 0xf];
    }
    *out = 0x00;
    return;
}

/* MD5
 * Hashing algorithm
 * md5hash() performs the hash of a given file.
 */
void md5hash(char *filein)
{
	FILE *fp = NULL;
	unsigned int tmpsize=0,linesize=0;
	char *hashbuf = NULL;
	unsigned char *hash = NULL;
	EVP_MD_CTX ctx;

	printf("MD5 hash of '%s' file is:\n",filein);
	EVP_DigestInit(&amp;<span class="entity">ctx</span>,EVP_md5()); /* initializes digest context*/
	fp = fopen(filein,"r");
	while ((linesize = getline(&amp;<span class="entity">hashbuf</span>,&amp;<span class="entity">tmpsize</span>,fp)) != -1) {
		EVP_DigestUpdate(&amp;<span class="entity">ctx</span>,hashbuf,linesize); /* hashes
		linesize bytes of data at hashbuf */
		linesize = 0;
	}
	fclose(fp);
	hash = (unsigned char *)malloc(16);
	EVP_DigestFinal(&amp;<span class="entity">ctx</span>,(unsigned char *)hash,NULL); /* retrieves
	the digest value */
	make_hex(hash, hashbuf);
	printf("%s\n",hashbuf);
	free(hashbuf);
	free(hash);
	return;
}

/* MD5
 * Hashing algorithm
 * md5cmp() compares the hash of two given files.
 */
void md5cmp(char *file1, char *file2)
{
	FILE *fp = NULL;
	unsigned int tmpsize=0,linesize=0;
	char *hashbuf = NULL;
	unsigned char *hash1 = NULL, *hash2 = NULL;
	EVP_MD_CTX ctx;

	printf("Comparing MD5 hashes of '%s' and '%s' files.\n",\
	file1,file2);
	EVP_DigestInit(&amp;<span class="entity">ctx</span>,EVP_md5());
	fp = fopen(file1,"r");
	while ((linesize = getline(&amp;<span class="entity">hashbuf</span>,&amp;<span class="entity">tmpsize</span>,fp)) != -1) {
		EVP_DigestUpdate(&amp;<span class="entity">ctx</span>,hashbuf,linesize);
		linesize = 0;
	}
	fclose(fp);
	hash1 = (unsigned char *)malloc(16);
	EVP_DigestFinal(&amp;<span class="entity">ctx</span>,(unsigned char *)hash1,NULL);
	EVP_DigestInit(&amp;<span class="entity">ctx</span>,EVP_md5()); /* initializes the digest
	context */
	linesize = 0;
	tmpsize = 0;
	fp = fopen(file2, "r");
	while ((linesize = getline(&amp;<span class="entity">hashbuf</span>,&amp;<span class="entity">tmpsize</span>,fp)) != -1) {
		EVP_DigestUpdate(&amp;<span class="entity">ctx</span>,hashbuf,linesize); /* hashes
		linesize bytes of data at hashbuf */
		linesize = 0;
	}
	fclose(fp);
	hash2 = (unsigned char *)malloc(16);
	EVP_DigestFinal(&amp;<span class="entity">ctx</span>,(unsigned char *)hash2,NULL); /* retrieves
	the digest value */
	if (strcmp(hash1,hash2) == 0)
	  printf("MD5 hashes match.\n");
	else
	  printf("MD5 hashes don't match.\n");
	free(hash1);
	free(hash2);
	free(hashbuf);
	return;
}
-------------------end hash.c------------------------------------------

-------------------misc.c----------------------------------------------
void help(char *name)
{
	printf("UniSFED [Simple File Encrypter/Decrypter] v%s\n",\
	VERSION);
	printf("Coded by Paolo Ardoino &lt;<span class="start-tag">paolo.ardoino@gmail.com</span>&gt;\n");
	printf("Usage:\n");
	printf("%s -h\t:displays this help\n",name);
	printf("%s -fh &lt;<span class="start-tag">file_to_hash</span>&gt;\t:performs the MD5 hash of \
	file_to_hash.\n",name);
	printf("%s -fc &lt;<span class="start-tag">file1_to_cmp</span>&gt; &lt;<span class="start-tag">file2_to_cmp</span>&gt;\t:compares the \
	MD5 hash of the two files.\n",name);
	printf("%s -e &lt;-idea|-des|-bf|-rsa&gt; &lt;<span class="start-tag">file_to_crypt</span>&gt; \
	&lt;<span class="start-tag">file_output</span>&gt; [rsa_pub.pem]]\t:encrypts file_to_crypt with \
	choosen cipher.\n",name);
	printf("%s -d &lt;-idea|-des|-bf|-rsa&gt; &lt;<span class="start-tag">file_to_decrypt</span>&gt; \
	&lt;<span class="start-tag">file_output</span>&gt; [rsa_sec.pem]\t:decrypts file_to_decrypt with choosen cipher.\n",name);
	printf("%s -grsa &lt;<span class="start-tag">numbits</span>&gt; &lt;<span class="start-tag">secfile</span>&gt; &lt;<span class="start-tag">pubfile</span>&gt;\t:generates a \
	RSA key pair.\n", name);
	printf("-idea: idea block cipher.\n");
	printf(" -des: des block cipher.\n");
	printf("  -bf: blowfish block cipher.\n");
	printf("Ex: %s -e -bf passwords.txt crypto_pass.txt\n",name);
	printf("Ex: %s -d -bf crypto_pass.txt pass_file.txt\n",name);
	printf("Ex: %s -fc file1 file2\n",name);
	printf("\nPlease report bugs to &lt;<span class="start-tag">ardoino.gnu@disi.unige.it</span>&gt;\n");
	return;
}

/*
 * fexists() checks for the existence of a given file.
 * return 0 if the file doesn't exist and 1 if it exists.
 */
int fexists(char *file)
{
	FILE *fp;
	if ((fp = fopen(file,"r")) == NULL) {
		return 0;
	} else {
		fclose(fp);
		return 1;
	}
}
-------------------end misc.c------------------------------------------

-------------------rsa.c-----------------------------------------------
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;</pre>
<pre id="line542">#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">err.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;

#define READPUB 0
#define READSEC 1

void rsa_ed(int mode, char *fin, char *fout, char *pemfile)
{
	int size=0,len=0,ks=0;
	RSA *key=NULL;
	FILE *fpin=NULL, *fpout=NULL;
	unsigned char *cipher=NULL,*plain=NULL;

	if (strcmp(fin, fout) == 0) {
		fprintf(stderr,"Error: input and output files must not\
		be the same file.\n");
		exit(EXIT_FAILURE);
	}
	if (mode == 0) {
		fpin = fopen(fin, "r");
		key = (RSA *)readpemkeys(READPUB, pemfile);
       		fpout = fopen(fout, "w");
		ks = RSA_size(key);
		plain = (unsigned char *)malloc(ks * \
		sizeof(unsigned char));
		cipher = (unsigned char*)malloc(ks * \
		sizeof(unsigned char));
		printf("Encrypting '%s' file.\n", fin);
		while(!feof(fpin)) {
			memset(plain,'\0',ks + 1);
			memset(cipher, '\0', ks + 1);
			len = fread(plain, 1, ks - 11, fpin);
			size = rsa_encrypt(key, plain, len, &amp;<span class="entity">cipher</span>);
			fwrite(cipher, 1, size, fpout);
		}
		fclose(fpout);
		fclose(fpin);
		free(cipher);
		free(plain);
		RSA_free(key);
		printf("Done.\n");
	} else if (mode == 1) {
		fpin = fopen(fin, "r");
		key = (RSA *)readpemkeys(READSEC, pemfile);
		fpout = fopen(fout, "w");
		ks = RSA_size(key);
		cipher = (unsigned char*)malloc(ks * \
		sizeof(unsigned char));
		plain = (unsigned char*)malloc(ks * \
		sizeof(unsigned char));
		printf("Decrypting '%s' file.\n", fin);
		while(!feof(fpin)) {
			memset(cipher, '\0', ks);
			memset(plain, '\0', ks);
			if ((len = fread(cipher, 1, ks, fpin)) == 0)
 			break;
         		size = rsa_decrypt(key, cipher, len, &amp;<span class="entity">plain</span>);
			fwrite(plain, 1, size, fpout);
       		}
		fclose(fpout);
		fclose(fpin);
		free(plain);
		free(cipher);
		RSA_free(key);
		printf("Done.\n");
	}
	return;
}

void genkey(int size, char *secfile, char *pubfile)
{
  RSA *key=NULL;
  FILE *fp;

  printf("Generating RSA keys[%d bits].\n", size);
  if (size &lt; 64) {
    fprintf(stderr, "Error: RSA Key pair size too small.\n");
    fprintf(stderr, "size &gt;= 64\n");
    exit(EXIT_FAILURE);
  }
  if((key = RSA_generate_key(size,3,NULL,NULL)) == NULL) {
    fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
    exit(EXIT_FAILURE);
  }
  if(RSA_check_key(key) &lt; 1) {
    fprintf(stderr,"Error: Problems while generating RSA Key.\n \
    Retry.\n");
    exit(EXIT_FAILURE);
  }
  fp=fopen(secfile,"w");
  if(PEM_write_RSAPrivateKey(fp,key,NULL,NULL,0,0,NULL) == 0) {
    fprintf(stderr,"Error: problems while writing RSA Private \
    Key.\n");
    exit(EXIT_FAILURE);
  }
  fclose(fp);
  fp=fopen(pubfile,"w");
  if(PEM_write_RSAPublicKey(fp,key) == 0) {
    fprintf(stderr,"Error: problems while writing RSA Public Key.\n");
    exit(EXIT_FAILURE);
  }
  fclose(fp);
  RSA_free(key);
  printf("Done.\n");
  return;
}

void* readpemkeys(int type, char *pemfile)
{
  FILE *fp;
  RSA *key=NULL;

  if(type == READPUB) {
    if((fp = fopen(pemfile,"r")) == NULL) {
      fprintf(stderr,"Error: Public Key file doesn't exists.\n");
      exit(EXIT_FAILURE);
    }
    if((key = PEM_read_RSAPublicKey(fp,NULL,NULL,NULL)) == NULL) {
      fprintf(stderr,"Error: problems while reading Public Key.\n");
      exit(EXIT_FAILURE);
    }
    fclose(fp);
    return key;
  }
  if(type == READSEC) {
    if((fp = fopen(pemfile,"r")) == NULL) {
      fprintf(stderr,"Error: Private Key file doesn't exists.\n");
      exit(EXIT_FAILURE);
    }
    if((key = PEM_read_RSAPrivateKey(fp,NULL,NULL,NULL)) == NULL) {
      fprintf(stderr,"Error: problmes while reading Private Key.\n");
      exit(EXIT_FAILURE);
    }
    fclose(fp);
    if(RSA_check_key(key) == -1) {
      fprintf(stderr,"Error: Problems while reading RSA Private Key in \
      '%s' file.\n",pemfile);
      exit(EXIT_FAILURE);
    } else if(RSA_check_key(key) == 0) {
      fprintf(stderr,"Error: Bad RSA Private Key readed in '%s' \
      file.\n",pemfile);
      exit(EXIT_FAILURE);
    }
    else
      return key;
  }
  return key;
}

int rsa_encrypt(void *key, unsigned char *plain, int len, \
unsigned char **cipher)
{
  int clen=0;

  srand(time(NULL));
  if((clen = RSA_public_encrypt(len, plain, *cipher, (RSA*)key, \
  RSA_PKCS1_PADDING)) == -1) {
    fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
    exit(EXIT_FAILURE);
  } else
    return clen;
}

int rsa_decrypt(void *key, unsigned char *cipher, int len, \
unsigned char **plain)
{
  int plen=0;

  if((plen = RSA_private_decrypt(len, cipher, *plain, (RSA*)key, \
  RSA_PKCS1_PADDING)) == -1) {
    fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
    exit(EXIT_FAILURE);
  } else
    return plen;
}
-------------------end rsa.c-------------------------------------------

-------------------unisfed.c-------------------------------------------
#include "unisfed.h"

int main(int argc, char *argv[])
{
	if (argc == 1 || strcmp(argv[1],"-h") == 0 || \
	((strcmp(argv[1],"-e") != 0 &amp;&amp; strcmp(argv[1],"-d") != 0 &amp;&amp; \
	strcmp(argv[1],"-fh") != 0 &amp;&amp; strcmp(argv[1],"-fc") != 0 &amp;&amp; \
	strcmp(argv[1], "-grsa") != 0)))
		help(argv[0]);
	else if (strcmp(argv[1],"-d") == 0 &amp;&amp; (argc == 5 || argc == 6) \
	&amp;&amp; (strcmp(argv[2],"-idea") == 0 ||strcmp(argv[2],"-des") == 0 \
	|| strcmp(argv[2],"-bf") == 0||strcmp(argv[2], "-rsa") == 0)){ \
		if (strcmp(argv[2],"-idea") == 0) {
			if (fexists(argv[3]) == 1)
				idea_encrypt_decrypt(0,argv[3],argv[4]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else if (strcmp(argv[2],"-des") == 0) {
			if (fexists(argv[3]) == 1)
				des_encrypt_decrypt(0,argv[3],argv[4]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else if (strcmp(argv[2],"-bf") == 0) {
			if (fexists(argv[3]) == 1)
				bf_encrypt_decrypt(0,argv[3],argv[4]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else if (strcmp(argv[2],"-rsa") == 0) {
			if (fexists(argv[3]) == 1)
				rsa_ed(1, argv[3], argv[4], argv[5]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else;
	} else if (strcmp(argv[1],"-e") == 0 &amp;&amp; \
	(argc == 5 || argc == 6) &amp;&amp; (strcmp(argv[2],"-idea") == 0 || \
	strcmp(argv[2],"-des") == 0 || strcmp(argv[2],"-bf") == 0 || \
	strcmp(argv[2], "-rsa") == 0)) {
		if (strcmp(argv[2],"-idea") == 0) {
			if (fexists(argv[3]) == 1)
				idea_encrypt_decrypt(1,argv[3], \
				argv[4]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else if (strcmp(argv[2],"-des") == 0) {
			if (fexists(argv[3]) == 1)
				des_encrypt_decrypt(1,argv[3],argv[4]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else if (strcmp(argv[2],"-bf") == 0) {
			if (fexists(argv[3]) == 1)
				bf_encrypt_decrypt(1,argv[3],argv[4]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else if (strcmp(argv[2],"-rsa") == 0) {
			if (fexists(argv[3]) == 1)
				rsa_ed(0, argv[3], argv[4], argv[5]);
			else fprintf(stderr,"Error: input file not \
			found.\n");
		} else;
	} else if (strcmp(argv[1],"-fh") == 0 &amp;&amp; argc == 3) {
		if (fexists(argv[2]) == 1)
			md5hash(argv[2]);
		else fprintf(stderr,"Error: input file not found.\n");
	} else if (strcmp(argv[1],"-fc") == 0 &amp;&amp; argc == 4) {
		if (fexists(argv[2]) == 1 &amp;&amp; fexists(argv[3]) == 1)
			md5cmp(argv[2],argv[3]);
		else fprintf(stderr,"Error: input files not found.\n");
	} else if (strcmp(argv[1], "-grsa") == 0 &amp;&amp; argc == 5)
		genkey(atoi(argv[2]), argv[3], argv[4]);
	else
		help(argv[0]);
	return 0;
}
-------------------end unisfed.c---------------------------------------

-------------------unisfed.h-------------------------------------------
#define _GNU_SOURCE
#include &lt;<span class="start-tag">stdio.h</span>&gt;</pre>
<pre id="line800">#include &lt;<span class="start-tag">stdlib.h</span>&gt;
#include &lt;<span class="start-tag">string.h</span>&gt;

#define VERSION "0.1"

/* Miscellaneous functions */
int fexists(char *file);
void help(char *name);

/* RSA fucntions */
void* readpemkeys(int type, char *pemfile); /*RSA*/
void genkey(int size, char *secfile, char *pubfile);/*RSA*/
int rsa_encrypt(void *key, unsigned char *plain, int len, \
unsigned char **cipher);/*RSA*/
int rsa_decrypt(void *key, unsigned char *cipher, int len, \
unsigned char **plain);/*RSA*/

/* Block ciphers fucntions */
void bf_encrypt_decrypt(int mode, char *filein, \
char *fileout); /* BlowFish */
void des_encrypt_decrypt(int mode, char *filein, \
char *fileout); /* DES */
void idea_encrypt_decrypt(int mode, char *filein, \
char *fileout); /* IDEA */

/* Hash functions */
void md5cmp(char *file1, char *file2); /* MD5 */
void md5hash(char *filein); /* MD5 */

#include "rsa.c"
#include "block_ciphers.c"
#include "hash.c"
#include "misc.c"
-------------------end unisfed.h---------------------------------------</pre>
]]></content:encoded>
			<wfw:commentRss>http://ardoino.com/21-openssl-des-blowfish-idea-md5-implementation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenSSL/RSA: toolkit &amp; implementation ( for Ondaquadra E-zine )</title>
		<link>http://ardoino.com/20-openssl-rsa-implementation/</link>
		<comments>http://ardoino.com/20-openssl-rsa-implementation/#comments</comments>
		<pubDate>Sat, 09 Feb 2008 07:00:04 +0000</pubDate>
		<dc:creator>Paolo Ardoino</dc:creator>
				<category><![CDATA[Crypto/Security]]></category>
		<category><![CDATA[Italian]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[cryptography]]></category>
		<category><![CDATA[Maths]]></category>
		<category><![CDATA[openssl]]></category>
		<category><![CDATA[rsa]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://ardoino.com/20-openssl-rsa-implementation/</guid>
		<description><![CDATA[[This article appeared on OndaQuadra0A Elettronic Magazine - Nov 2003 ]
OpenSSL/RSA: toolkit &#38; implementation
Article &#38;&#38; sources by Paolo Ardoino AKA binduck
&#60;paolo.ardoino@gmail.com&#62;

0.    Intro
1     RSA - Teoria
1.1   OpenSSL/RSA [genrsa,rsa,rsautl]
	(generare chiave,cifrare/decifrare,firmare,...)
1.1.1 GPG
1.2   Impariamo ad implementare RSA nei nostri programmi
1.2.1 RSA - Headers
1.2.2 RSA - Le chiavi
1.2.3 RSA [...]]]></description>
			<content:encoded><![CDATA[<pre>[This article appeared on OndaQuadra0A Elettronic Magazine - Nov 2003 ]
OpenSSL/RSA: toolkit &amp; implementation
Article &amp;&amp; sources by Paolo Ardoino AKA binduck
&lt;<span class="start-tag">paolo.ardoino@gmail.com</span>&gt;

0.    Intro
1     RSA - Teoria
1.1   OpenSSL/RSA [genrsa,rsa,rsautl]
	(generare chiave,cifrare/decifrare,firmare,...)
1.1.1 GPG
1.2   Impariamo ad implementare RSA nei nostri programmi
1.2.1 RSA - Headers
1.2.2 RSA - Le chiavi
1.2.3 RSA - Cifrare e decifrare

0. Intro

In questo articolo voglio illustrarvi le basi che vi permetteranno di
capire e implementare l' algoritmo RSA.
1]Vedremo, quindi, come utilizzare il toolkit openssl (ne vedremo le
principali funzioni, come creare le chiavi, come cifrare/decifrare
dati).
2]Vedremo insieme le basi delle librerie openssl, e in particolare
quelle che vi permetteranno di implementare l'algoritmo nei vostri
programmi.

Per affrontare la lettura di questo articolo avrete bisogno di
conoscere:
- il linguaggio C
- se volete comprendere la parte matematica dovrebbe bastare
l'infarinatura di matematica fornitavi nelle elementari e nelle medie.
- dovreste avere openssl e le librerie (/usr/include/openssl/) se vi
mancano....installatele.
<span id="more-20"></span>
1 RSA - Teoria

RSA fu sviluppato da tre matematici del MIT:Rivest, Shamir e Adleman:

- Cifrario a chiave pubblica (usato nel PGP e in molti altri programmi)
- Si basa sulla teoria matematica dei numeri; infatti le chiavi sono
costituite dal prodotto di due numeri primi molto grandi(piu' di
trecento cifre)
- Cifrazione/Decifrazione di dati
- Firma/Controllo firma
- Supporta chivi di diversa grandezza in modo da fornire vari livelli
di sicurezza (grandezza minima consigliata e' 1024).

Riprendiamo alcuni concetti basilari della crittografia che ci saranno
utili. Un cifrario a chiave pubblica (o cifrario asimmetrico) e'
basato sull'utilizzo di due chiavi,una per cifrare e una per decifrare.
La prima chiave puo' essere distribuita a chi vuole farci pervenire
messaggi cifrati in modo che solo noi possiamo decifrarli con la nostra
chiave segreta(che DEVE rimanere segreta).
Il fatto che la chiave pubblica possa essere tranquillamente
distribuita anche via email, in messaggi in chiaro, elimina la
necessita' di utilizzare canali altamente sicuri per lo scambio della
chiave utilizzata nei cifrari a chiave semplice.

Iniziamo a vedere l'algoritmo in generale ed a analizzarlo dal punto
di vista matematico.
1)Il cifrario RSA e' basato sul prodotto di due numeri primi di grandi
dimensioni, che possono superare le 300 cifre.
Ricordo inanzitutto che un numero si dice primo solo se e' divisibile
per 1 e se stesso.
Noi prenderemo due numeri primi piccoli per fare un esempio:
P = 7 e Q = 11
2)Ora chiamiamo N il prodotto dei due: N = P * Q = 77
3)Ora calcoliamo il valore della funzione di Eulero di N in questo
modo:
M = f(n) = (P-1)*(Q-1)
Nel nostro caso M = 60
Vi ricordo che il valore della funzione di Eulero dovra' rimanere
segreto.
4)Ora scegliamo un numero E tale che E e M siano primi tra loro.
Poiche' 1 &lt; E &lt; M allora iniziamo a dividere M per tutti i numeri
maggiori di 1 fino a che non troviamo un numero che abbia una parte
decimale.
60 / 2 = 30
60 / 3 = 20
60 / 4 = 15
60 / 5 = 12
60 / 6 = 10
60 / 7 = 8.57
Quindi E = 7
5)Ora calcoliamo D usando la formula D = ((H * M) + 1) / E
in modo che H sia il piu' piccolo valore per cui D sia intero.
Quindi iniziamo a sostituire H con i numeri 1,2,3,... fintanto che il
risultato trovato non sia intero.
D = ((1 * 60) + 1) / 7 -&gt; NO
D = ((2 * 60) + 1) / 7 -&gt; NO
....
....
D = ((5 * 60) + 1) / 7 = 301 / 7 = 43

D = 43
6)Bene ora abbiamo generato la nostra chiave che useremo per
crifrare/decifrare i dati. Per cifrare usiamo la formula:
C = (B^E) mod N
Dove C e' il testo cifrato, mentre B e' il valore decimale del
testo che vogliamo cifrare.
Prendiamo come esempio B = 3 -&gt;
C = (3 ^ 7) mod 77 = 31
Per decifrare usiamo la formula:
L = (C^D) mod N
Prendiamo ora il numero precedentemente ottenuto e decifriamolo:
L = (31 ^ 43) mod 77 = 3

Nota: si potrebbe pensare che si possa semplicemente calcolare la
funzione di Eulero senza utilizzare i numeri primi P e Q. Questo non e'
impossibile ma richiede un ingente quantita' di tempo, avendo lo stesso
grado di complessita' della fattorizzazione di N.

1.1 OpenSSL/RSA

Vediamo ora come utilizzare openssl in combinazione con RSA.
Creiamo inanzitutto le chiavi RSA, e per fare questo si usa openssl
genrsa:
openssl genrsa [-out nome_file] [-passout arg] [-des] [-des3]
[-idea] [-f4] [-3] [-rand file(s)] [numbits]

binduck@fuzzy:~$ openssl genrsa -des3 1024 &gt; key.pem
Con questo comando generiamo una chiave RSA di lunghezza 1024 bits
e la salviamo nel file key.pem nel formato PEM.
Verra' chiesto di inserire una password per cifrare la chiave
con 3des prima di salvarla(possiamo sostituire -des3 con -des o -idea).
Se invece non vogliamo cifrarla basta fare eliminarel'opzione -des3:
binduck@fuzzy:~$ openssl genrsa 1024 &gt; key.pem

Vediamo le altre opzioni del comando openssl genrsa:
-out file_out  :Il nome del file di output.
-passout arg   :Il file sorgente delle password per l'output.
-F4|-3         :L'esponente pubblico da usare(65537 o 3(default 65537))
numbits        :Numero di bits(minimo consigliato 1024).

PER MAGGIORI INFORMAZIONI SULLE OPZIONI: genrsa(1)

Ora ricaviamo la chiave pubblica da quella privata appena generata,
utilizzando openssl rsa:
openssl rsa[-inform] [-outform |PEM|NET|DER] [-in filename]
[-passin arg] [-out filename] [passout arg] [-sgckey] [-des] [-des3]
[-idea] [-text] [-noout] [-modulus] [-check] [-pubin] [-pubout]
-in file	:Legge la chiave RSA contenuta nel file passato come
argomento.(Per default la chiave sara' intesa come privata).
-pubin		:Dichiara che la chiave letta con -in file sara'
pubblica.
-pubout		:Dichiara che l'output sara' una chiave pubblica.

binduck@fuzzy:~$ openssl rsa -in key.pem -pubout &gt; pub.pem
o in maniera equivalente:
binduck@fuzzy:~$ openssl rsa -in key.pem -pubout -out pub.pem
Vediamo le altre opzioni interessanti:
-check		:Controlla la struttura di una chiave privata RSA.
binduck@fuzzy:~$ openssl rsa -check -in key.pem

Altre opzioni utili sono quelle che permettono di cifrare una chiave,
con un algoritmo a scelta tra des, 3des, idea, in un secondo momento
dalla creazione della chiave.
binduck@fuzzy:~$ openssl rsa -in key.pem -des3 -out key.pem
A questo punto bastera' digitare la pass phrase, confermarla e la
vostra chiave sara' cifrata.

Ovviamente possiamo essere interessati a rimuovere la password
dalla chiave:
binduck@fuzzy:~$ openssl rsa -in key.pem -out keydec.pem
Dovrete inserire la pass phrase per eliminare la cifratura e il
gioco e' fatto.

-modulus	:Stampa il modulo della chiave.
binduck@fuzzy:~$ openssl rsa -in key.pem -modulus

PER MAGGIORI INFORMAZIONI SULLE ALTRE OPZIONI: rsa(1)

Ora passiamo a vedere come cifrare/decifrare,firmare/verificare dati
usando l'algoritmo RSA.
openssl rsautl [-in file][-out file][-inkey file][pubin][-certin]
[-sign][-verify][-encrypt] [-decrypt][-pkcs][-ssl][-raw][-hexdump]
[-asn1parse]

NOTA: rsautl, poiche' usa l'algoritmo RSA direttamente puo' essere
usato solo per cifrare dati di piccole dimensioni.
Se tentiamo di firmare un file troppo grande verra' generato un errore
che ci dira' appunto che la dimensione del file era troppo elevata per
la chiave usata.
-inkey file  :Usa la chiave contenuta nel file passato come argomento.
(Per default rsautl si aspettera' una chiave privata).
-pubin	     :Dichiara che la password contenuta nel file letto
con -inkey file e' una chiave pubblica.
-certin      :Dichiare che l'input sara' un certificato contentente una
chiave RSA.

Prendiamo come esempio un file contenente una password.
echo "rsa_algorithm" &gt; pass.txt
Ora per cifrare il file digitiamo:
binduck@fuzzy:~$ openssl rsautl -encrypt -in pass.txt -inkey pub.pem
 -pubin&gt; crypto
Ora avremo la nostra password cifrata nel file "crypto".
Ovviamente pub.pem e' la chiave pubblica precedentemente generata con
openssl genrsa.

Vediamo ora il processo inverso, decifriamo la password:
binduck@fuzzy:~$ openssl rsautl -decrypt -in crypto -inkey key.pem
Questo stampera' sullo stdout la password in chiaro.
key.pem e' la chiave privata, poiche' stiamo decifrando.

Mettiamo il caso che vogliamo semplicemente firmare un documento
usando la nostra chiave privata(anche nel caso delle firme possiamo
firmare solo dati di piccole dimensioni).
binduck@fuzzy:~$ openssl rsautl -sign -in small_file.txt -inkey key.pem
 -out signed_file

Vediamo ora come verificare dei dati firmati:
binduck@fuzzy:~$ openssl rsautl -verify -in signed_file -inkey key.pem

PER MAGGIORI INFORMAZIONE SULLE ALTRE OPZIONI: rsautl(1)

1.1.1 GPG
Se vi siete rotti delle limitazioni insite nell'uso di rsautl a causa
della dimensione dei file vi consiglio di usare gpg.
Pero' per quanto riguarda l'utilizzo di RSA in gpg bisogna ricordare
che questo algoritmo e' usato solo per le firme.
Ci sono ottime guide dedicate a questo programma, prima fra tutte il
manuale che potrete trovare a questo indirizzo:
http://www.gnupg.org/(en)/documentation

1.2 Impariamo ad implementare RSA nei nostri programmi.

Ora passiamo alla parte piu' interessante:
Impariamo come implementare RSA nei nostri programmi.

1.2.1 RSA - Headers
Qui e' riportata la lista di headers che utilizzeremo per creare dei
programmini di base.

#include&lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;
Funzioni per generare le chiavi, cifrare, decifrare, firmare,
verificare dati.
-----------------------------
#include&lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;
Funzioni per leggere e scrivere strutture in formato PEM.
Noi le utilizzeremo per salvae le chiavi RSA nei files.
Ricordate openssl genrsa che salva le chiavi generate in formato PEM.
-----------------------------
#include&lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">err.h</span>&gt;</pre>
<pre id="line261">Funzioni per accedere ai codici di errore generati dalle funzioni della
libreria openssl.
-----------------------------

1.2.2 RSA - Le chiavi

Vediamo la struttura di una chiave RSA:
struct
{
	BIGNUM *n;	//public modulus
	BIGNUM *e;	//public exponent
	BIGNUM *d;	//private exponent
	BIGNUM *p;	//secret prime factor
	BIGNUM *q;	//secret prime factor
	BIGNUM *dmp1;	// d mod (p-1)
	BIGNUM *dmq1;	// d mod (q-1)
	BIGNUM *iqmp;	// q^-1 mod p
};
RSA

Ovviamente nelle chiavi pubbliche l'esponente privato(d) e i relativi
valori segreti (p e q) sono NULL (per chiarirvi le idee potete andare
a rivedervi la trattazione matematica al paragrafo 1).
Nelle chiavi private p, q, dmp1, dmq1 e iqmp potrebbero anche essere
NULL, ma le operazioni effettuate usando questa chiave risulterebbero
piu' lente.
Ricordiamo infatti che per decifrare si usa solo d (guardatevi sempre
il par.1).

Vediamo come creare le chiavi.
Prima presentero' le funzioni necessarie e poi vedremo un semplice
programma per creare le nostre chiavi.
Inanzitutto dobbiamo allocare e iniziare una struttura RSA.
Questo e' possibile con la funzione RSA_new():
---------------------------------------------------------------------
#include&lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;
RSA * RSA_new(void);
Ritorna NULL se fallisce l'allocazione; l'errore puo' essere ottenuto
usando ERR_get_error() (spiegata piu' avanti).
Come potete vedere dal programma per crear le chiavi usando la funzione
RSA_generate_key() la struttura viene direttamente inizializzata.
---------------------------------------------------------------------
RSA_free() libera la memoria occupata dalla struttura RSA, ma prima di
fare cio' cancella la chiave.
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;
RSA_free(RSA *rsa);
Ricordatevi di liberare sempre la memoria occupata dalle vostre chiavi.
---------------------------------------------------------------------
Per creare le chiavi usiamo la funzione RSA_generate_key():
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;
RSA *RSA_generate_key(int num, unsigned long e, void(*callback)
(int,int,void *), void *cb_arg);
int num: numero di bit. Come dice la man page e' meglio scegliere una
chiave &gt;= di 1024 bit.
unsigned long e: e' l'esponente. Deve essere un numero dispari,
tipicamente si sceglie 3, 17 o 65537.
Se la funzione fallisce ritorna NULL.  Il numero dell'errore puo'
essere ottenuto sempre con ERR_get_error().
---------------------------------------------------------------------
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;
int RSA_check_key(RSA *rsa);
Questa funzione controlla se la chiave e' una vera chiave RSA.
Se e' corretta allora la funzione ritorna 1, se non e' una chiave
ritorna 0, mentre se la funzione fallisce ritorna -1.
---------------------------------------------------------------------
Ora che sappiamo come creare la nostra chiave vediamo come scrivere
la chiave privata in un file.
Possiamo usare una funzione presente in pem.h:
PEM_write_RSAPrivateKey():
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;
int PEM_write_RSAPrivateKey(FILE *fp,RSA *x,const EVP_CIPHER *enc,
unsigned char *kstr,int klen,pem_password_cb *cb,void *u);
---------------------------------------------------------------------
Mentre per scrivere la chiave pubblica useremo
PEM_write_RSAPublicKey():
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;
int PEM_write_RSAPublicKey(FILE *fp,RSA *x);
Tutte e due queste funzioni di scrittura ritornano 1 se hanno successo
e 0 se falliscono.
---------------------------------------------------------------------
Per leggere la chiave privata scritta in formato pem usiamo
PEM_read_RSAPrivateKey():
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;
RSA *PEM_read_RSAPrivateKey(FILE *fp,RSA **x,pem_password_cb *cb,
void *u);
---------------------------------------------------------------------
Per leggere la chiave pubblica usiamo PEM_read_RSAPublicKey():
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;
RSA *PEM_read_RSAPublicKey(FILE *fp,RSA **x,pem_password_cb *cb,
void *u);
Le funzioni di lettura ritornano un puntatore alla struttura letta o
NULL se c'e' un errore.
Settiamo enc, cb, kstr e u a NULL e poniamo klen a 0 poiche' non
necessitiamo di crittare le strutture PEM.
---------------------------------------------------------------------
Ora sappiamo come creare e salvare le nostre chiavi.
Prima di vedere un esempio pratico introduciamo anche le funzioni
per il controllo degli errori.
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">err.h</span>&gt;</pre>
<pre id="line361">unsigned long ERR_get_error(void);
Questa funzione ritorna il codice dell'ultimo errore.
---------------------------------------------------------------------
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">err.h</span>&gt;
char *ERR_error_string(unsigned long e, char *buf);
Genera una stringa "human-readable".
Un utilizzo di queste due funzioni combinate e' questo:
printf("%s\n",ERR_error_string(ERR_get_error(),NULL));
---------------------------------------------------------------------
Bene ora vediamo un piccolo esempio su come creare una chiave e
salvarla su dei files.
-----------------------------keygen.c--------------------------------
/*
	Simple RSA Key generator. Saves keys in PEM format.
	Coded by Paolo Ardoino - &lt;paolo.ardoino@gmail.com<span class="start-tag"></span>&gt;
	Compile: gcc -lssl keygen.c -o keygen
	Usage: ./keygen &lt;<span class="start-tag">numbits</span>&gt;
	Ex. ./keygen 1024

*/

#include &lt;<span class="start-tag">stdio.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">err.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;
#define SECFILE "sec.pem"
#define PUBFILE "pub.pem"
int main(int argc, char *argv[])
{
 RSA *key;
 FILE *fp;
 int keylen=0;
 if(argc!=2)
 {
  fprintf(stderr,"Error: too many/few arguments.\n "
  "Usage: %s &lt;<span class="start-tag">numbits</span>&gt;\n",argv[0]);
  exit(0);
 }
 keylen = atoi(argv[1]);
 if((key = RSA_generate_key(keylen,3,NULL,NULL)) == NULL)
 {
  fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
  exit(-1);
 }
 if(RSA_check_key(key) &lt; 1)
 {
 fprintf(stderr,"Error: Problems while generating RSA Key.\nRetry.\n");
 exit(-1);
 }
 fp=fopen(SECFILE,"w");
 if(PEM_write_RSAPrivateKey(fp,key,NULL,NULL,0,0,NULL) == 0)
 {
  fprintf(stderr,"Error: problems while writing RSA Private Key.\n");
  exit(-1);
 }
 fclose(fp);
 fp=fopen(PUBFILE,"w");
 if(PEM_write_RSAPublicKey(fp,key) == 0)
 {
  fprintf(stderr,"Error: problems while writing RSA Public Key.\n");
  exit(-1);
 }
 fclose(fp);
 RSA_free(key);
 printf("RSA key generated.\nLenght = %d bits.\n",keylen);
 return 0;
}

---------------------------------------------------------------------
Per compilare digitate: gcc -lssl keygen.c -o keygen
Usage: ./keygen &lt;<span class="start-tag">numbits</span>&gt;</pre>
<pre id="line432">binduck@fuzzy:~$ ./keygen 1024
Eseguendo il programma, questo ci creera' due files 'pub.pem' e
'sec.pem' in cuiverranno salvate le nostre chiavi RSA.
Ovviamente potrete specificare la lunghezza da voi desiderata
(Es. 64 o 512 o 2048).
Ecco come risulterebbe una chiave privata a 1024 bit generata.

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDWxE5+qNqE20NQWqRi71vkqroI+52CgzGmKv42BsE6kk1QiVSS
9Qm75bKfEP7Jz83NO/YO5DPHp6ZVr38nY6HCY3Ta/fNU0O/xNE3UiOQSK8dn7lbw
7itshIwjPpK09cgL6wos4Sm+lcHjdRk5DyTKcRNadWyXSxNsdrR5FWtImwIBAwKB
gQCPLYmpxecDPNeK5xhB9Oftxyawp75XAiEZcf7Oryt8YYjgW423TgZ9Q8xqC1SG
iokzfU60mCKFGm7jylTE7RaAXuiq84NDz71wmFjOgqGzePHl4CH5WnPi0GTwfssI
cEBr5WjUu2DTNKAUdk+1jLJFXFY6UIws6tzZB1SPNNagewJBAPAvdSm765vsMcOL
zfIks0rMpx9c4QZrXAgm+IoAN3EQOvZ9KNAK1xkUYDPJEyJ93GY5ZjyPaFnM9t+x
n97l1r8CQQDk6GVm8oN9Z5aMPNDSzNGrj+f+xxngEjxDzcH2YfDcVy8cb8T4Daqt
vWSP2JWZm4YAWJzACuuQ+zAMBAJnQ4ElAkEAoB+jcSfyZ/LL17KJTBh3hzMaFOiW
BEeSsBn7BqrPoLV8pFNwirHku2LqzTC3bFPoRCZEKF+a5oiklSEVP0PkfwJBAJia
7kShrP5FDwgoizczNnJf7/8vZpVhfYKJK/mWoJLkyhL1Lfqzxx5+QwqQY7u9BAA7
Eyqx8mCndV1YAZotAMMCQQDYZg4eFgmTJuq/J/Ls7NusdBxuwh0fKRt2KPhCZw5r
5mEeCDflQ3ATBjeUt6Z77JG0aEmQUq5NOqd/ju1VtBst
-----END RSA PRIVATE KEY-----

Ed ecco la chiave pubblica relativa:

-----BEGIN RSA PUBLIC KEY-----
MIGHAoGBANbETn6o2oTbQ1BapGLvW+Squgj7nYKDMaYq/jYGwTqSTVCJVJL1Cbvl
sp8Q/snPzc079g7kM8enplWvfydjocJjdNr981TQ7/E0TdSI5BIrx2fuVvDuK2yE
jCM+krT1yAvrCizhKb6VweN1GTkPJMpxE1p1bJdLE2x2tHkVa0ibAgED
-----END RSA PUBLIC KEY-----

1.2.3 Cifrare/Decifrare

Nell'header openssl/rsa.h troviamo le funzioni di cui abbiamo
bisogno: RSA_private_decrypt() e RSA_public_encrypt().
---------------------------------------------------------------------
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;
int RSA_public_encrypt(int flen, unsigned char *from,
unsigned char *to,RSA *rsa,int padding);
unsigned char *from: stringa da crittografare.
unsigned char *to: buffer dove la funzione mette l'output
crittografato.
RSA *rsa: chiave pubblica RSA.
Come padding impostiamo RSA_PKCS1_OAEP_PADDING
Ritorna la grandezza dei dati crittografati.
---------------------------------------------------------------------
int RSA_private_decrypt(int flen,unsigned char *from,unsigned char
*to,RSA *rsa,int padding);
unsigned char *from: stringa da decrittare.
unsigned char *to: buffer che conterra' l'output in chiaro.
RSA *rsa: chiave privata RSA.
Come padding impostiamo sempre RSA_PKCS1_OAEP_PADDING.
Ritorna la grandezza del testo in chiaro.
---------------------------------------------------------------------
Bene ora vediamo un programmino che cifra e decifra il contenuto di
un file.

RICORDO CHE STIAMO USANDO DIRETTAMENTE L'ALGORITMO RSA, QUINDI
POSSIAMO INTERVENIRE SU UNA PICCOLA QUANTITA' DI DATI(ricordate
rsautl nella prima parte dell'articolo?).

--------------------------file_crypt.c-------------------------------
/*

	Simple RSA encrypting/decrypting tool.
	Coded by binduck - &lt;<span class="start-tag">binduck@coder.hu</span>&gt;
	Compile: gcc -lssl file_crypt.c -o file_crypt
	Usage: ./file_crypt -h    for help

*/

#include &lt;<span class="start-tag">stdio.h</span>&gt;
#include &lt;<span class="start-tag">stdlib.h</span>&gt;
#include &lt;<span class="start-tag">unistd.h</span>&gt;
#include &lt;<span class="start-tag">string.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">pem.h</span>&gt;
#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">err.h</span>&gt;</pre>
<pre id="line511">#include &lt;<span class="start-tag">openssl</span><span class="error"><span class="attribute-name">/</span></span><span class="attribute-name">rsa.h</span>&gt;

#define SECFILE "sec.pem"
#define PUBFILE "pub.pem"

#define READPUB 0
#define READSEC 1

#define HELP 'h'
#define GENKEY 'g'
#define CIPHER 'c'
#define DECIPHER 'd'

RSA* readpemkeys(int type);
void genkey(int size);
int rsa_encrypt(RSA *key, unsigned char *plain, int len, unsigned char **cipher);
int rsa_decrypt(RSA *key, unsigned char *cipher, int len, unsigned char **plain);

int main(int argc,char *argv[])
{
  int ch,size=0,len=0,ks=0;
  RSA *key=NULL;
  FILE *fpin=NULL, *fpout=NULL;
  char char_opt[] = {HELP,GENKEY,CIPHER,DECIPHER};
  unsigned char *cipher=NULL,*plain=NULL;

  printf("RSA Cipher/Decipher\n");
  printf("Coded by Paolo Ardoino - &lt;<span class="start-tag">ardoino.gnu@disi.unige.it</span>&gt;\n\n");
  if (argc == 1)
    printf("'%s -h' for help.\n", *argv);
  while((ch=getopt(argc,argv,char_opt)) != -1) {
   switch(ch) {
     case HELP:
       printf("%s -g &lt;<span class="start-tag">num_bits</span>&gt;\n", *argv);
       printf("\tgenerates RSA keys and save them in PEM format.(1024 or 2048 are strongly suggested).\n");
       printf("%s -c &lt;<span class="start-tag">file_in</span>&gt; &lt;<span class="start-tag">file_out</span>&gt;\n", *argv);
       printf("\tcrypts datas in 'file_in' and stores output in 'file_out'.\n");
       printf("%s -d &lt;<span class="start-tag">file_in</span>&gt; &lt;<span class="start-tag">file_out</span>&gt;\n", *argv);
       printf("\tdecript datas in 'file_in' and stores output in 'file_out'.\n");
     break;

     case GENKEY:
       if(argc != 3) {
         fprintf(stderr,"Error: check arguments.\n'%s -h' for help.\n",*argv);
         exit(EXIT_FAILURE);
       }
       ks = atoi(*(argv + 2));
       printf("Generating RSA keys [size = %d bits]\n", ks);
       genkey(ks);
       printf("Private Key saved in %s file.\n", SECFILE);
       printf("Public Key saved in %s file.\n", PUBFILE);
       printf("Done.\n");
     break;

     case CIPHER:
       if(argc != 4) {
         fprintf(stderr,"Error: check arguments.\n'%s -h' for help.\n", *argv);
         exit(EXIT_FAILURE);
       }
       key = readpemkeys(READPUB);
       if(!(fpin = fopen(*(argv + 2), "r"))) {
         fprintf(stderr, "Error: Cannot locate input file.\n");
         exit(EXIT_FAILURE);
       }
       fpout = fopen(*(argv + 3), "w");
       ks = RSA_size(key);
       plain = (unsigned char *)malloc(ks * sizeof(unsigned char));
       cipher = (unsigned char*)malloc(ks * sizeof(unsigned char));
       printf("Encrypting '%s' file.\n",*(argv + 2));
       while(!feof(fpin)) {
         memset(plain,'\0',ks + 1);
         memset(cipher, '\0', ks + 1);
         len = fread(plain, 1, ks - 11, fpin);
         size = rsa_encrypt(key, plain, len, &amp;<span class="entity">cipher</span>);
         fwrite(cipher, 1, size, fpout);
       }
       fclose(fpout);
       fclose(fpin);
       free(cipher);
       free(plain);
       RSA_free(key);
       printf("Done.\n");
     break;

     case DECIPHER:
       if(argc != 4) {
         fprintf(stderr,"Error: check arguments.\n'%s -h' for help.\n", *argv);
         exit(EXIT_FAILURE);
       }
       key = readpemkeys(READSEC);
       if(!(fpin = fopen(*(argv + 2), "r"))) {
         fprintf(stderr, "Error: Cannot locate input file.\n");
         exit(EXIT_FAILURE);
       }
       fpout = fopen(*(argv + 3), "w");
       ks = RSA_size(key);
       cipher = (unsigned char*)malloc(ks * sizeof(unsigned char));
       plain = (unsigned char*)malloc(ks * sizeof(unsigned char));
       printf("Decrypting '%s' file.\n", *(argv + 2));
       while(!feof(fpin)) {
         memset(cipher, '\0', ks);
         memset(plain, '\0', ks);
         if ((len = fread(cipher, 1, ks, fpin)) == 0)
 	  break;
         size = rsa_decrypt(key, cipher, len, &amp;<span class="entity">plain</span>);
         fwrite(plain, 1, size, fpout);
       }
       fclose(fpout);
       fclose(fpin);
       free(plain);
       free(cipher);
       RSA_free(key);
       printf("Done.\n");
      break;
    }
  }
  return 0;
}

void genkey(int size)
{
  RSA *key=NULL;
  FILE *fp;

  if((key = RSA_generate_key(size,3,NULL,NULL)) == NULL) {
    fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
    exit(EXIT_FAILURE);
  }
  if(RSA_check_key(key) &lt; 1) {
    fprintf(stderr,"Error: Problems while generating RSA Key.\nRetry.\n");
    exit(EXIT_FAILURE);
  }
  fp=fopen(SECFILE,"w");
  if(PEM_write_RSAPrivateKey(fp,key,NULL,NULL,0,0,NULL) == 0) {
    fprintf(stderr,"Error: problems while writing RSA Private Key.\n");
    exit(EXIT_FAILURE);
  }
  fclose(fp);
  fp=fopen(PUBFILE,"w");
  if(PEM_write_RSAPublicKey(fp,key) == 0) {
    fprintf(stderr,"Error: problems while writing RSA Public Key.\n");
    exit(EXIT_FAILURE);
  }
  fclose(fp);
  RSA_free(key);
  return;
}

RSA* readpemkeys(int type)
{
  FILE *fp;
  RSA *key=NULL;

  if(type == READPUB) {
    if((fp = fopen(PUBFILE,"r")) == NULL) {
      fprintf(stderr,"Error: Public Key file doesn't exists.\n");
      exit(EXIT_FAILURE);
    }
    if((key = PEM_read_RSAPublicKey(fp,NULL,NULL,NULL)) == NULL) {
      fprintf(stderr,"Error: problems while reading Public Key.\n");
      exit(EXIT_FAILURE);
    }
    fclose(fp);
    return key;
  }
  if(type == READSEC) {
    if((fp = fopen(SECFILE,"r")) == NULL) {
      fprintf(stderr,"Error: Private Key file doesn't exists.\n");
      exit(EXIT_FAILURE);
    }
    if((key = PEM_read_RSAPrivateKey(fp,NULL,NULL,NULL)) == NULL) {
      fprintf(stderr,"Error: problmes while reading Private Key.\n");
      exit(EXIT_FAILURE);
    }
    fclose(fp);
    if(RSA_check_key(key) == -1) {
      fprintf(stderr,"Error: Problems while reading RSA Private Key in '%s' file.\n",SECFILE);
      exit(EXIT_FAILURE);
    } else if(RSA_check_key(key) == 0) {
      fprintf(stderr,"Error: Bad RSA Private Key readed in '%s' file.\n",SECFILE);
      exit(EXIT_FAILURE);
    }
    else
      return key;
  }
  return key;
}

int rsa_encrypt(RSA *key, unsigned char *plain, int len, unsigned char **cipher)
{
  int clen=0;

  srand(time(NULL));
  if((clen = RSA_public_encrypt(len, plain, *cipher, key, RSA_PKCS1_PADDING)) == -1) {
    fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
    exit(EXIT_FAILURE);
  } else
    return clen;
}

int rsa_decrypt(RSA *key, unsigned char *cipher, int len, unsigned char **plain)
{
  int plen=0;

  if((plen = RSA_private_decrypt(len, cipher, *plain, key, RSA_PKCS1_PADDING)) == -1) {
    fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
    exit(EXIT_FAILURE);
  } else
    return plen;
}
---------------------------------------------------------------------
readpemkeys() e' un esempio di come e' possibile leggere le chiavi
salvate in formato PEM.
Il codice e' molto semplice e quindi non ritengo necessario commenti.

E con questo programmino io avrei terminato questo articolo, che spero
vi abbia chiarito le idee su RSA e openssl.
Per eventuali chiarimenti potete scrivermi a paolo.ardoino@gmail.com</pre>
<pre id="line511">Grazie a tutti e alla prossima.</pre>
]]></content:encoded>
			<wfw:commentRss>http://ardoino.com/20-openssl-rsa-implementation/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
