Red de conocimiento informático - Material del sitio web - Cómo implementar el algoritmo RSA en C

Cómo implementar el algoritmo RSA en C

Presentamos el algoritmo RSA y la implementación de JAVA. De hecho, Java es casi lo mismo que C. Consúltelo

lt;conceptos básicos

El algoritmo RSA es muy simple. se resume de la siguiente manera:

Encontrar Encuentra dos números primos p y q

Tomar n=p*q

Tomar t=(p-1)*(q -1)

Tome cualquier Se requiere un número e para satisfacer elt, y e y t son primos relativos (es decir, el máximo común divisor es 1)

Tome cualquier número e que satisfaga los requisitos de elt, y e y t son primos relativos (es decir, el máximo común divisor es 1) es 1)

Tome d*et==1

El resultado tiene tres números. : n d e

Establezca la información en el número M (M lt; n)

Establezca c=(M**d)n, obtenga la información cifrada c

Establecer m=(c)

Establecer m=(c)n, obtener la información cifrada c.

Nota: ** representa la potencia de dos, y d y e en las dos ecuaciones anteriores se pueden intercambiar.

En cifrado simétrico:

n d dos números constituyen una clave pública, que se puede comunicar a otros

n e dos números constituyen una clave privada, e es; guardado por uno mismo, nadie puede saberlo.

La información enviada a otros se cifra con e. Siempre que otros puedan descifrarla con d, demuestra que la información fue enviada por usted, lo que constituye un mecanismo de firma.

Otros te envían mensajes cifrados con d, por lo que sólo tú con e puedes descifrar el mensaje.

La seguridad de rsa es que para números grandes n, no existe una forma efectiva de descomponerlo.

Por lo tanto, si conoce n d, no puede obtener e si conoce n Par; si hay una e, no se puede obtener d.

lt;二GT;Ejercicio

A continuación, haremos un ejercicio:

Comprende cómo funciona:

Echa un vistazo Mira a dos personas que te envían mensajes para ver cómo funciona.

Encuentra dos números primos:

p=47

q=59

De esta manera

n= p*q=2773

t=(p-1)*(q-1)=2668

Tome e=63, que satisface elt y es consistente con e y t Números mutuamente primos

Usa Perl para realizar una enumeración exhaustiva simple. Puedes usar el número completo e*dt == 1 para obtener el número d:

C:\Tempgt; perl -e "foreach $i (1..9999){ print($i),last if $i*632668==1 }"

847

Es decir, d = 847

Finalmente tenemos la clave

n=2773

d=847

e=63

Con la información M=244 como Por ejemplo, echemos un vistazo

Cifrado:

c=M**dn = 244**8472773

Usar perl's cálculo de números grandes:

C:\Tempgt; perl -Mbigint -e "print 244**8472773"

465

es decir, use d para cifrar M y obtener la información cifrada c = 465

Descifrado:

Podemos descifrar la c cifrada restaurando M usando e:

m=c** es =465**632773:

C:\Tempgt; perl -Mbigint -e "print 465**632773"

244

Es decir, use e para descifrar c y obtener m = 244, que es igual a la Información M original.

lt; IIIgt; Cifrado de cadenas

Combinado con el proceso anterior, podemos implementar un ejemplo de cifrado y descifrado de cadenas.

Tome el valor ascii de un carácter en la cadena cada vez y calcúlelo como M. La salida es una cadena de números hexadecimales cifrados

Un número en forma de 3 bytes, como 01F

El código es el siguiente:

#! /usr/bin/perl -w

El programa de aprendizaje del proceso de cálculo #RSA está escrito como un programa de prueba

#watercloud 2003-8-12

#

usa estricto;

usa Math::BigInt;

mi RSA_ CORE = (n=gt; 2773, e=gt; 63, d=gt; 847) ; #p=47, q=59

mi $N=nueva Matemática::BigInt($RSA_CORE{n});

mi $E=nueva Matemática:: BigInt( $RSA_CORE{e});

mi $D=new Math::BigInt($RSA_CORE{d});

print "N=$N D=$D E= $E \n";

sub RSA_ENCRYPT

{

mi $r_mess = shift @_;

mi ($c, $i ,$M,$C,$cmess);

for($i=0;$i lt; longitud($$r_mess);$i )

{

$c=ord(substr($$r_mess, $i, 1));

$M=Math.:BigInt-gt; nuevo($c); >

$C=$M-gt;copia(); $C-gt;bmodpow($D,$N);

$c=sprintf "03X",$C;

$cmess.=$c;

}

return \$cmess;

}

sub RSA_DECRYPT

{

mi $r_mess = shift @_;

mi ($c, $i, $M, $C, $dmess);

for($i=0;$i lt.length($$r_mess);$i =3)

{

$c=substr($$r_mess ,$ i, 3);

$c=hex($c);

$M=Math::BigInt-gt; nuevo($c);

$C=$M-gt; copiar(); $C-gt; bmodpow($E, $N); p> $dmess.=$c;

}

devuelve \$dmess;

}

mi $mess="RSA waaahahaahaahaahaaha~ ~~";

$mess=$ARGV[0] if @ARGV gt;= 1;

print "Cadena original:",$mess,"\n" ;

mi $r_cmess = RSA_ENCRYPT(\$mess);

imprimir "Cadena cifrada:",$$r_cmess,"\n";

mi $ r_dmess = RSA_DECRYPT($r_

cmess);

print "Cadena descifrada:",$$r_dmess,"\n";

#EOF

Pruébalo:

C:\Tempgt;perl 3393EC12F0A466E0AA9510D025D7BA0712DC3379F47D51C325D67B

Cadena descifrada: enfoque seguro (xfocus)

lt;fourgt; mejorar

Como se mencionó anteriormente, la seguridad de rsa proviene del hecho de que n es lo suficientemente grande y el n que usamos en nuestras pruebas es muy pequeño.

Podemos obtener N y D E suficientemente grandes mediante herramientas como RSAKit y RSATool.

Usando estas herramientas, podemos obtener los 1024 Bit n y D E para realizar pruebas:

N = 0x328C74784DF3119C526D18098EBEBEB943B599cee13CC2b5FCD15F90B66EC3A85F5005D

BDCDED9BDCB3C4C 265AF164AD55884D8278F79A6BFDAD5C4F017F9CCF1538D4C20134383B

47d80EC74B5D6346346346346346346346346346346346346346346346346346346 3463466346634663466346346634663466346634663466B9E E5AD2D7BE7ABFB36E37108dd60438941d2ed173CCA50E114705D7E2

BC511951

d=0x10001

e=0xE760A3804ACDE1E8E3D7DC0197F9CEF6282EF552E8CEBBB7434B01CB19A9D87A3106DD28C523C2995

4C5D8 43080E4919CA8CE08718C3B0930867A98F635EB9EA9200B25906D91B80A47B77324E66AFF2

C4D70D8B1C69C50A9D8B4B7A3C9EE05FFF3A16AFC02373 4763DA1DCABE9861A4789BD782A592D2B

1965

Establecer información original

M= 0x11111111111122222222222233333333333

Para completar un cálculo de números tan grande, necesita usar una biblioteca de aritmética de números grandes, y es muy Perl fácil de usar para calcular:

A) Cifre M con d de la siguiente manera:

c=M***dn:

C:\Tempgt. perl - Mbigint -e "$x=Math::BigInt-gt;bmodpow(0x11111111111111222222222222233

33333333333, 0x10001, 0x328C74784DF31119C526D18098EBEBB943B00 32B 599CEE13CC2BCE7B5F

CD15F90B66EC3A85F5005DBDCDED9BDFCB3C4C265AF164AD55884D8278F791C7A6BFDAD55EDBC4F0

17F9CCF1538D4C2013433B383B47D 8 0EC74B51276CA05B5D6346B9EE5AD2D7BE7ABFB36E37108DD6

0438941D2ED173CCA50E114705D7E2BC511951);imprimir $x-gt;as_hex"

0x17b287be418c69ecd7c39227ab681ac422fcc84bb35d8a632543b304de288a8d4434b7 3 d2576bd

45692b007f3a2f7c5f5aa1d99ef3866af26a8e876712ed1d4cc4b293e26bc0a1dc67e247715caa6b

3028

f9461a3b1533ec0cb476441465f10d8ad47452a12db0601c5e8beda686dd96d2acd59ea89b91

f1834580c3f6d90898

es decir, la información cifrada con d is

c=0 be418c69ecd7c39227ab681ac422fcc84bb35d8a632543b304de288a8d4434b73d2576bd

45692b007f3a2f7c5f5aa1d99ef3866af26a8e876712ed1d e26bc0a1dc67e247715caa6b

3028f9461a3b1533ec0cb476441465f10d8ad47452a12db0601c5e8beda686dd96d2acd59ea89b91

f1834580c3f6d90898

B) Utilice e para descifrar c de la siguiente manera:

m=c **en: >

C:\Tempgt; -Mbigint -e "$x=Math::BigInt-gt;bmodpow(0x17b287be418c69ecd7c39227ab

681ac422fcc84bb35d8a632543b304de288a8d4434b73d2576bd45692b007f3a2f7 5aa1d99ef3

866af26a8e876712ed1d4cc4b293e26bc0a1dc67e247715caa6b3028f9461a3b1533ec0cb4764414

65f10d8ad47452a12db0601 c5e8beda686dd 96d2acd59ea89b91f1834580c3f6d90898,0xE760A

3804ACDE1E8E3D7DC0197F9CEF6282EF552E8CEBBB7434B01CB19A9D87A3106DD28C523C29954C5D

86B36E943080E4919CA8CE08718C3B0930867A98F63 EB9EA9200B25906D91B80A47B77324E66AFF

2C4D70D8B1C69C50A9D8B4B7A3C9EE05FFF3A16AFC023731D80634763DA1DCABE9861A4789BD782A

592 1965,0x328c74784df31119c526d18098ebeb943b0032b599cee13cc2bce7b5fcd15f90

B66EC3A85F5005DBDCDED9BDFCB3C4C265AF164AD55884D8278F791C7 55EDBC4F017F9CCF

1538D4C2013433B383B47D80EC74B51276CA05B5D6346B9EE5AD2D7BE7ABFB36E37108DD60438941

D2ED173CCA50E114705D7E2BC511951); el cálculo tarda unos 5 segundos en mi máquina P4 1.6G)

>

Utilice e= 0x111111111111222222222223333333333 == M para obtener el m descifrado

C) La implementación habitual de RSA

RSA es simple y elegante, pero la velocidad de cálculo es lenta y se usa generalmente en cifrado. No se usa directamente para cifrar toda la información.

El escenario más común es generar aleatoriamente una clave de cifrado simétrica y luego usar la clave de cifrado simétrica para cifrar toda la información. La situación más común es generar aleatoriamente una clave de cifrado simétrica, luego usar un algoritmo de cifrado simétrico para cifrar la información y luego usar

RSA para cifrar la clave de cifrado recién cifrada.

Finalmente, cabe señalar que actualmente se ha demostrado que N menores de 1024 bits son inseguros

No utilice RSA menores de 1024 bits usted mismo, es mejor usar 2048 bits.

------------------------------------------- ---------------

Implementación simple del algoritmo RSA en código fuente JAVA:

nombre de archivo: RSA.java

/*

* Creado el 3 de marzo de 2005

*

* TODO Para cambiar la plantilla de este archivo generado, visite

* Ventana - Preferencias - Java - Estilo de código - Plantillas de código

*/

importar java.IOException

importar java.io.FileWriter

importar java.io.FileReader

importar java.io.StringTokenizer

/**

* @autor Steve

*

*

* TODO Para cambiar la plantilla para esta anotación de tipo generada, visite

* Ventana - Preferencias - Java - Estilo de código - Código Plantillas

*/

clase pública RSA {

/**

* BigInteger.private static final BigInteger ZERO = BigInteger.ZERO

/**

* BigInteger.ONE

*/

privado estático final BigInteger ONE = BigInteger.ONE

p >

/**

* Pseudo BigInteger.ONE

*/

privado estático final BigInteger ONE = BigInteger.ONE;

/**

* Pseudo BigInteger.ONE/UTWO

*/

BigInteger final estático privado DOS = new BigInteger("2");

BigInteger myKey privado

BigInteger myMod privado

tamaño de bloque int privado

RSA público (clave BigInteger, BigInteger n, int; b ) {<

miClave = clave

miMod = n;

tamaño de bloque = b; p > public void encodeFile (nombre de archivo de cadena) {

byte[] bytes = nuevo byte[ blockSize / 8 1];

byte[] temp; int tempLen;

InputStream es = null;

Fi

leWriter escritor = null;

intente {

es = nuevo FileInputStream(nombre de archivo);

escritor = nuevo FileWriter(nombre de archivo ".enc");

p>

}

catch (FileNotFoundException e1){

System .out.println("Archivo no encontrado: " nombre de archivo);

}

catch (IOException e1){

System.out.println("Archivo no encontrado: " nombre de archivo ".enc");

}

/**

* Escribe la información codificada en 'filename'.enc

*/

prueba {

while ((tempLen = is.read(bytes, 1, blockSize / 8)) gt; 0) {

for (int i = tempLen 1; i lt; bytes.length; i ) {

bytes[i] = 0;

}

escritor.write(encodeDecode( new BigInteger(bytes)) " "); >

}

}

catch (IOException e1) {

System.out.println("error al escribir en el archivo");

}

/**

* Cerrar el flujo de entrada y el escritor de archivos

*/

intentar {

es.close();

escritor.close();

}

captura (IOException e1) {

System.out.println("Error al cerrar el archivo.");

}

}

}

public void decodeFile (nombre de archivo de cadena) {

lector FileReader = nulo

OutputStream os = nulo

prueba {

lector = nuevo FileReader( nombre de archivo);

os = new FileOutputStream( filename.replaceAll(".enc", ".dec"));

}

catch (FileNotFoundException e1 ) {

if (lector == null)

System.out.println("Archivo no encontrado: " nombre de archivo

else

);

System.out.println("El archivo no es f

sonido: " filename.replaceAll(".enc", "dec"));

}

BufferedReader br = new BufferedReader(lector);

int desplazamiento;

byte[] temp, toFile;

StringTokenizer st = null

prueba {

while (br.ready( )) {

st = new StringTokenizer(br.readLine());

while (st.hasMoreTokens()){

toFile = encodeDecode(new BigInteger(st.nextToken())).toByteArray();

System.out.println(toFile.length " x " (blockSize / 8));

if (toFile [0] == 0 amp; toFile.length ! = (blockSize / 8)) {

temp = nuevo byte[blockSize / 8];

offset = temp. longitud - toFile.length

if (toFile[0] == 0 amp; amp; toFile.length !length;

for (int i = toFile.length - 1; (i lt; = 0)) amp; ((i desplazamiento) lt; = 0) {

temp[i desplazamiento] = toFile[i];

}

toFile = temp;

}

/*if (toFile.length != ((blockSize / 8) 1)){

temp = nuevo byte[(blockSize / 8) 1];

System.out.println(toFile.length " x " temp.length

); for (int i = 1; i lt; temp.length; i) {

temp[i] = toFile[i - 1]

}

toFile = temp;

}

else

System.out.println(toFile.length " " ((bloque))).

longitud " " ((blockSize / 8) 1));*/

os.write(toFile);

}

}

}

catch (IOException e1) {

System.out.println("¿Algo para archivar?println("Algo salió mal");

}

/**

* Cerrar el flujo de datos

*/

prueba {

os.close ( );

lector.close( );

}

captura (IOException e1) {

System.out.println( "Error al cerrar el archivo.");

}

}

}

/**

* en lt;ttgt;baselt;/ttgt;^lt;supgt;lt;ttgt;powlt;/ttgt;lt;/supgt; Modularización

* Ejecutar lt;ttgt;modlt;/ttgt en el dominio

*

* @param base La base a elevar

* @param pow El poder de la base a elevar

* @param mod El dominio del módulo para realizar esta operación

* @return lt;ttgt;baselt;/ttgt;^lt;supgt;lt;ttgt;powlt;/ttgt;lt;/supgt ; inlt; ttgt;modlt;/ttgt; dentro del dominio del módulo

*/

public BigInteger encodeDecode(BigInteger base) {

BigInteger a = UNO;

BigInteger s = base;

BigInteger n = myKey;

while (!n.equals(ZERO)) {

if (!n.mod(DOS).equals(ZERO))

a = a.multiply(s).mod(myMod);

s = s .pow(2).mod( myMod);

n = n.divide(DOS); /p>

}

}