-
Notifications
You must be signed in to change notification settings - Fork 0
/
iarsac.cpp
413 lines (339 loc) · 12.2 KB
/
iarsac.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
// IARSAC - Versión 0.3
// Implementación del Algoritmo RSA en C++
//
// Copyright (C) 2003-4 Pablo De Napoli
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// ChangeLog
// 0.1- initial release
// 0.2- cast to unsigned char* to fix compilation warnings
// change of the encrypted format: add a length for each block
// to avoid problems with the size of the last block
// 0.3 - error messages if problems when reading public/private keys
// support for multiple users
// Usamos la libreria NTL para numeros de gran tamaño
// ZZ es la clase de NTL para enteros de gran tamaño
#include <NTL/ZZ.h>
using namespace NTL;
// Usamos la clase string de la libreria standard
using namespace std;
#include <string>
// y la clase ifstream para leer /dev/random
#include <fstream>
#include <getopt.h>
#include <assert.h>
// Variables Globales
long longitud_de_clave=100;
string usuario;
enum {no_valida,show_help,generar_claves,cifrar,descifrar,show_license};
// la accion no_valida es cero
bool verbose=0;
class encriptador_rsa
{
public:
void generar_claves(long longitud);
void cifrar(istream& texto_plano,ostream& texto_encriptado);
void descifrar(istream& texto_encriptado,ostream& texto_plano);
void establecer_parametros();
ZZ n;
ZZ clave_publica;
ZZ clave_privada;
private:
// n sera el tamaño del "alfabeto" en el cual vamos a cifrar o
// descifrar
long longitud_de_clave;
long long_bloque_plano;
long long_bloque_encriptado;
};
void encriptador_rsa::generar_claves(long longitud)
{
ZZ p;
ZZ q;
ZZ phi_n;
// Elegimos (al azar) dos números primos (grandes) distintos
// ZZ es el tipo de datos "entero grande" de la libreria NTL
p = GenPrime_ZZ(longitud);
do
{
q = GenPrime_ZZ(longitud);}
while (p==q);
n = p*q;
phi_n = (p-1)*(q-1);
if (verbose)
{
cerr << "Generando claves RSA para " << usuario << "\n";
cerr << "longitud de clave=" << longitud << " bits \n";
cerr << "Primos elegidos \n";
cerr << "p=" << p << "\n";
cerr << "q=" << q << "\n";
};
// la clave privada debe ser un numero (al azar) que no tenga factores
// en comun con (p-1)*(q-1)
do {
clave_publica = RandomLen_ZZ(longitud)%n;
} while (GCD(clave_publica,phi_n)!=1);
// la clave publica es el inverso modulo phi_n de la clave publica
if (verbose)
{
cerr << "clave_publica=" << clave_publica << "\n";
cerr << "n=" << n << "\n";
cerr << "phi_n=" << phi_n << "\n";
};
clave_privada = InvMod(clave_publica,phi_n);
if (verbose)
cerr << "clave_privada=" << clave_privada << "\n";
}
void encriptador_rsa::cifrar(istream& texto_plano,ostream& texto_encriptado)
{
ZZ numero_plano,numero_encriptado;
char* bloque_plano = new char[long_bloque_plano+1]; // 1 para un cero al final
char* bloque_encriptado = new char[long_bloque_encriptado+1];
long input_count = 0;
long output_count =0;
while (1)
{
texto_plano.read(bloque_plano,long_bloque_plano);
int count=texto_plano.gcount(); // cuantos bytes fueron leidos
input_count = input_count + count;
if (count==0) break;
// escribe una cabecera de bloque conteniendo la longitud
// del bloque a convertir
if (verbose)
cerr << "long. de bloque plano=" << count <<"\n";
texto_encriptado.write((char*)&count,sizeof(count));
// completa el bloque con ceros para que tenga exactamente
// long_bloque_plano bytes y pone un cero al final (para que
// sea un C-string valido)
char* p = bloque_plano + count;
while (count <= long_bloque_plano)
{
*p = '\0';
count++;
p++;
};
if (verbose) cerr << "Bloque a convertir= \"" << bloque_plano << "\"\n";
numero_plano = ZZFromBytes((unsigned char*) bloque_plano,long_bloque_plano);
if (verbose) cerr << "convertido a numero= " << numero_plano << "\n";
// Esta linea encripta
numero_encriptado = PowerMod(numero_plano,clave_publica,n);
if (verbose) cerr << "numero encriptado= " << numero_encriptado << "\n";
BytesFromZZ((unsigned char*)bloque_encriptado,numero_encriptado,long_bloque_encriptado);
*(bloque_encriptado+long_bloque_encriptado)='\0';
if (verbose) cerr << "bloque encriptado= \"" << bloque_encriptado << "\"\n";
texto_encriptado.write(bloque_encriptado,long_bloque_encriptado);
output_count = output_count + long_bloque_encriptado;
};
if (verbose)
{
cerr << "total de bytes leidos (texto plano)= "<< input_count << " \n";
cerr << "total de bytes escritos (texto encriptado)=" << output_count << "\n";
};
delete bloque_plano;
delete bloque_encriptado;
}
void encriptador_rsa::descifrar(istream& texto_encriptado,ostream& texto_plano)
{
ZZ numero_plano,numero_encriptado;
char* bloque_plano = new char[long_bloque_plano+1]; // 1 para un cero al final
char* bloque_encriptado = new char[long_bloque_encriptado+1];
long input_count = 0;
long output_count =0;
int count_from_file;
while (1)
{
// lee la cabecera de bloque: cuantos bytes de texto plano componen el
// bloque?
texto_encriptado.read((char*)&count_from_file,sizeof(count_from_file));
if (verbose)
cerr << "long bloque plano from file=" << count_from_file;
// Ahora leemos el bloque
texto_encriptado.read(bloque_encriptado,long_bloque_encriptado);
int count=texto_encriptado.gcount(); // cuantos bytes fueron leidos
if (count ==0) break;
input_count = input_count + count;
if (count < long_bloque_encriptado)
{
cerr << "count=" << count << "\n";
cerr << "Error al leer el archivo encriptado!\n";
abort();
};
// pone un cero al final (para que sea un C-string valido)
*(bloque_plano+long_bloque_plano)='\0';
if (verbose) cerr << "Bloque a descifrar= \"" << bloque_encriptado << "\"\n";
numero_encriptado = ZZFromBytes((unsigned char*)bloque_encriptado,long_bloque_encriptado);
if (verbose) cerr << "convertido a numero= " << numero_encriptado << "\n";
// Esta linea desencripta
numero_plano = PowerMod(numero_encriptado,clave_privada,n);
if (verbose) cerr << "numero plano= " << numero_plano << "\n";
BytesFromZZ((unsigned char*)bloque_plano,numero_plano,long_bloque_plano);
*(bloque_plano+count_from_file)='\0';
if (verbose) cerr << "bloque plano= \"" << bloque_plano << "\"\n";
texto_plano.write(bloque_plano,count_from_file);
output_count = output_count + count_from_file;
};
if (verbose)
{
cerr << "total de bytes leidos (texto encriptado)= "<< input_count << " \n";
cerr << "total de bytes escritos (texto plano)=" << output_count << "\n";
};
delete bloque_plano;
delete bloque_encriptado;
};
void encriptador_rsa::establecer_parametros()
{
long_bloque_plano = NumBytes(n)-1;
long_bloque_encriptado = NumBytes(n);
if (verbose)
{
cerr << "bloque_encriptado=" << long_bloque_encriptado << '\n';
cerr << "bloque_plano=" << long_bloque_plano << '\n';
}
};
int parse_command_line(int argc,char** argv)
{
static struct option long_options[] =
{
{ "cifrar-para", required_argument, 0,'c'},
{ "descifrar-para",required_argument,0,'d'},
{ "generar-claves-para",required_argument,0,'g'},
{ "verbose",no_argument,0,'v'},
{ "longitud-de-clave",required_argument,0,'l'},
{ "help",no_argument,0,'h'},
{ "license",no_argument,0,'L'},
{ 0, 0 , 0 , 0 }
};
int accion=0;
int option_index=0;
int c;
while (1)
{
c = getopt_long(argc,argv,"c:d:g:vl:hL",long_options,&option_index);
if (c == -1) break;
switch(c)
{
case 'l': if (optarg) longitud_de_clave=strtol(optarg,NULL,10);
break;
case 'v': verbose = 1;
break;
case 'g': accion=accion?no_valida:generar_claves;
if (optarg) usuario = optarg;
break;
case 'c': accion=accion?no_valida:cifrar;
if (optarg) usuario = optarg;
break;
case 'd': accion=accion?no_valida:descifrar;
if (optarg) usuario = optarg;
break;
case 'L': accion=accion?no_valida:show_license;
break;
case 'h':
default: accion=accion?no_valida:show_help;
}
};
return accion;
}
// funcion que lee bytes de /dev/random y lo utiliza como semilla para
// generar numeros aleatorios
void random_seed()
{
ifstream random;
int longitud=5;
char bytes_leidos[longitud];
random.open("/dev/random");
random.read(bytes_leidos,longitud);
random.close();
ZZ semilla = ZZFromBytes((unsigned char*)bytes_leidos,longitud);
SetSeed(semilla);
}
void mostrar_version()
{
cerr << "IARSAC version 0.3 \n";
cerr << "Implementacion en C++ del Algoritmo RSA \n";
cerr << "(C) 2003-4 por Pablo De Napoli \n\n";
};
int main(int argc,char** argv)
{
encriptador_rsa rsa;
string nombre_de_archivo;
int accion=parse_command_line(argc,argv);
switch (accion)
{
case generar_claves: {
random_seed();
rsa.generar_claves(longitud_de_clave);
ofstream of;
nombre_de_archivo = usuario + ".clave_publica";
of.open(nombre_de_archivo.c_str());
of << rsa.n << '\n';
of << rsa.clave_publica << '\n';
of.close();
nombre_de_archivo = usuario + ".clave_privada";
of.open(nombre_de_archivo.c_str());
of << rsa.n << '\n';
of << rsa.clave_privada << '\n';
of.close();
};
break;
case cifrar: {
ifstream f;
nombre_de_archivo = usuario + ".clave_publica";
f.open(nombre_de_archivo.c_str());
if (f.fail())
{
cerr << "error leyendo la clave pública para " << usuario << "\n";
exit(1);
};
f >> rsa.n;
f >> rsa.clave_publica;
f.close();
rsa.establecer_parametros();
rsa.cifrar(cin,cout);
};
break;
case descifrar: {
ifstream f;
nombre_de_archivo = usuario + ".clave_privada";
f.open(nombre_de_archivo.c_str());
if (f.fail())
{
cerr << "error leyendo la clave privada para "<< usuario << "\n";
exit(1);
};
f >> rsa.n;
f >> rsa.clave_privada;
f.close();
rsa.establecer_parametros();
rsa.descifrar(cin,cout);
};
break;
case show_license: mostrar_version();
cerr << "IARSAC es Software Libre y usted puede redistribuirlo o modificarlo \n";
cerr << "libremente, bajo las condiciones establecidas en la Licencia Publica GNU. \n";
cerr << "(GNU General Public Licence), version 2 o posterior (a su eleccion). \n \n";
cerr << "IARSAC se distribuye con la esperanza de que sea util \npero sin ningun tipo de garantia. \n";
break;
case no_valida: cerr << "Opcion(es) no valida(s) \n";
case show_help:
default: mostrar_version();
cerr << "Opciones:\n";
cerr << "-g --generar-claves-para usuario: genera las claves pública y privada \n";
cerr << "-c --cifrar-para usuario: encripta \n";
cerr << "-d --descifrar-para usuario: desencripta \n";
cerr << "-h --help: muestra esta ayuda \n";
cerr << "-L --license: muestra información sobre la licencia GPL \n";
cerr << "-l --longitud-de-clave \n";
cerr << "-v --verbose \n";
};
}