Criptosistemas de clave pública

Proteger la información en la era digital

Configuración del Entorno de Desarrollo Para demostrar el uso práctico de la criptografía de clave pública, crearemos una aplicación sencilla utilizando NetBeans. Puedes descargar e instalar NetBeans desde aquí. Una vez que hayas instalado NetBeans, crea un nuevo proyecto de Aplicación Web Java. Lo llamaremos «RSAExample». Comprendiendo el Algoritmo RSA RSA se basa en las…

Written by

×

Aplicación Práctica del Criptosistema de Clave Pública: Un Ejemplo de RSA

Configuración del Entorno de Desarrollo

Para demostrar el uso práctico de la criptografía de clave pública, crearemos una aplicación sencilla utilizando NetBeans. Puedes descargar e instalar NetBeans desde aquí.

Una vez que hayas instalado NetBeans, crea un nuevo proyecto de Aplicación Web Java. Lo llamaremos «RSAExample».

Comprendiendo el Algoritmo RSA

RSA se basa en las propiedades matemáticas de números primos grandes y su relativa dificultad para ser factorizados. El algoritmo se puede desglosar en los siguientes pasos clave:

  1. Generación de Pares de Claves: El proceso comienza con la generación de un par de claves: una clave pública y una clave privada. Estas claves están relacionadas matemáticamente, pero es computacionalmente inviable derivar una de la otra.
  2. Cifrado: Cuando alguien quiere enviar datos cifrados a otra parte, utiliza la clave pública del destinatario para cifrar la información. Esto garantiza que solo el destinatario, con su clave privada, pueda descifrar y leer el mensaje.
  3. Descifrado: El destinatario utiliza su clave privada para descifrar los datos, revelando así el mensaje original. La clave privada debe mantenerse en secreto para mantener la seguridad del sistema.

El Código Java

Veamos más de cerca el código Java proporcionado. El código demuestra la implementación práctica del algoritmo RSA utilizando el lenguaje de programación Java. A continuación, se presenta una descripción general de los principales componentes y funcionalidades:

Clase RSAExample:

package com.mycompany.rsaexample;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;

public class RSAExample {

    public static void main(String[] args) {
        // Definimos un texto a cifrar
        String plaintext = "Estudiante: Jonathan Zamudio Patarroyo";

        System.out.println("\nTexto a cifrar:");
        System.out.println(plaintext);

        // Instanciamos la clase RSA
        RSA rsa = new RSA();

        try {
            // Generamos un par de claves de 512 bits
            rsa.genKeyPair(512);

            String privateKeyFile = "c:/tmp/rsa.pri";
            String publicKeyFile = "c:/tmp/rsa.pub";

            // Guardamos las claves en disco para su uso posterior
            rsa.saveToDiskPrivateKey(privateKeyFile);
            rsa.saveToDiskPublicKey(publicKeyFile);

            // Ciframos el texto y almacenamos el resultado cifrado
            String encryptedText = rsa.Encrypt(plaintext);

            System.out.println("\nCifrado:");
            System.out.println(encryptedText);

            // Creamos otra instancia de RSA para descifrar
            RSA rsa2 = new RSA();

            // Cargamos las claves previamente guardadas
            rsa2.openFromDiskPublicKey(publicKeyFile);
            rsa2.openFromDiskPrivateKey(privateKeyFile);

            // Desciframos el texto cifrado
            String decryptedText = rsa2.Decrypt(encryptedText);

            // Imprimimos el texto descifrado
            System.out.println("\n Texto Descifrado:");
            System.out.println(decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Clase RSA:

package com.mycompany.rsaexample;

import java.io.BufferedReader;
import java.io.BufferedWriter;

import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;

import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/**
 *
 * @author User
 */
public class RSA {
    public PrivateKey PrivateKey = null;
    public PublicKey PublicKey = null;

    public RSA()
    {
        // Constructor vacío
    }
    
    /**
     * Establece la clave privada a partir de una representación de cadena.
     */
    public void setPrivateKeyString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException{
        byte[] encodedPrivateKey = stringToBytes(key);
        
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
        this.PrivateKey = privateKey;
    }

    /**
     * Establece la clave pública a partir de una representación de cadena.
     */
    public void setPublicKeyString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException{
        
        byte[] encodedPublicKey = stringToBytes(key);
        
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
        this.PublicKey = publicKey;
    }

    /**
     * Obtiene la representación en cadena de la clave privada.
     */
    public String getPrivateKeyString(){
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(this.PrivateKey.getEncoded());
        return bytesToString(pkcs8EncodedKeySpec.getEncoded());
    }

    /**
     * Obtiene la representación en cadena de la clave pública.
     */
    public String getPublicKeyString(){
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(this.PublicKey.getEncoded());
        return bytesToString(x509EncodedKeySpec.getEncoded());
    }
    
    /**
     * Genera un par de claves RSA de un tamaño dado.
     */
    public void genKeyPair(int size) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException  {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(size);
        KeyPair kp = kpg.genKeyPair();
        
        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();
        
        this.PrivateKey = privateKey;
        this.PublicKey = publicKey;
    }

    /**
     * Encripta un texto utilizando la clave pública.
     */
    public String Encrypt(String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, UnsupportedEncodingException, NoSuchProviderException {

        byte[] encryptedBytes; 
  
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, this.PublicKey);
        encryptedBytes = cipher.doFinal(plain.getBytes());

        return bytesToString(encryptedBytes);

    }

    /**
     * Desencripta un texto utilizando la clave privada.
     */
    public String Decrypt(String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

        byte[] decryptedBytes;

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, this.PrivateKey);
        decryptedBytes = cipher.doFinal(stringToBytes(result));
        return new String(decryptedBytes);
    }

    /**
     * Convierte un array de bytes en una cadena.
     */
    public String bytesToString(byte[] b) {
        byte[] b2 = new byte[b.length + 1];
        b2[0] = 1;
        System.arraycopy(b, 0, b2, 1, b.length);
        return new BigInteger(b2).toString(36);
    }

    /**
     * Convierte una cadena en un array de bytes.
     */
    public byte[] stringToBytes(String s) {
        byte[] b2 = new BigInteger(s, 36).toByteArray();
        return Arrays.copyOfRange(b2, 1, b2.length);
    }

    /**
     * Guarda la clave privada en un archivo en disco.
     */
    public void saveToDiskPrivateKey(String path) throws IOException {
        try {
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path), "UTF-8"));
            out.write(this.getPrivateKeyString());
            out.close();
        } catch (Exception e) {
            // Manejo de excepciones
        }
    }
    
    /**
     * Guarda la clave pública en un archivo en disco.
     */
    public void saveToDiskPublicKey(String path) {
        try {
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path), "UTF-8"));
            out.write(this.getPublicKeyString());
            out.close();
        } catch (Exception e) {
            // Manejo de excepciones
        }
    }

    /**
     * Carga la clave pública desde un archivo en disco.
     */
    public void openFromDiskPublicKey(String path) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        String content = this.readFileAsString(path);
        this.setPublicKeyString(content);
    }
    
    /**
     * Carga la clave privada desde un archivo en disco.
     */
    public void openFromDiskPrivateKey(String path) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        String content = this.readFileAsString(path);
        this.setPrivateKeyString(content);
    }
    
    /**
     * Lee el contenido de un archivo como una cadena.
     */
    private String readFileAsString(String filePath) throws IOException {
        StringBuffer fileData = new StringBuffer();
        BufferedReader reader = new BufferedReader(
                new FileReader(filePath));
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
        }
        reader.close();
        return fileData.toString();
    } 
}

Generación de Claves

El código comienza generando un par de claves RSA con un tamaño especificado (en este caso, 512 bits). El tamaño de la clave afecta al nivel de seguridad del cifrado. Tamaños de clave más grandes proporcionan una seguridad más sólida pero pueden ser más lentos en el procesamiento.

Las claves generadas se guardan en el disco para su uso futuro.

Cifrado

A continuación, un mensaje en texto plano, en este caso, «Estudiante: Jonathan Zamudio Patarroyo», se cifra utilizando la clave pública del destinatario. El resultado es un texto cifrado que solo se puede descifrar utilizando la clave privada correspondiente.

Descifrado

Para demostrar el proceso de descifrado, el código crea otra instancia de la clase RSA y carga las claves públicas y privadas previamente guardadas. Luego, descifra el texto cifrado para recuperar el mensaje original.

El texto descifrado debe coincidir con el mensaje en texto plano original.

Implicaciones Prácticas

El algoritmo RSA desempeña un papel crucial en la seguridad de datos en diversas aplicaciones del mundo real:

Comunicación Segura

RSA se utiliza comúnmente para asegurar la transmisión de datos por Internet. Cuando accede a un sitio web seguro (HTTPS), es frecuente que se emplee el cifrado RSA para proteger sus datos, como las credenciales de inicio de sesión y la información de pago, durante la transmisión.

Firmas Digitales

RSA se utiliza para crear firmas digitales que verifican la autenticidad e integridad de documentos y mensajes digitales. Las firmas digitales son vitales para garantizar la legitimidad de documentos electrónicos, contratos y correos electrónicos.

Almacenamiento Seguro de Archivos

Las organizaciones utilizan el cifrado RSA para proteger archivos y datos almacenados en servidores o en la nube. Esto garantiza que, incluso si se produce un acceso no autorizado, los datos permanezcan ilegibles sin la clave privada.

En resumen, el algoritmo RSA demuestra el poder de la criptografía de clave pública, permitiendo la comunicación segura y la protección de la información digital en diversos ámbitos.

Referencias:

Follow, S. (2019, May 28). Public key encryption. GeeksforGeeks. https://www.geeksforgeeks.org/public-key-encryption/

Wikipedia contributors. (2023, September 9). Public-key cryptography. Wikipedia, The Free Encyclopedia. https://en.wikipedia.org/w/index.php?title=Public-key_cryptography&oldid=1174652157

DeLeon, A. (2016, November 10). Encriptar y Desencriptar con RSA en JAVA – Alvaro De León. Alvaro De León; Alvaro DeLeon. https://www.alvarodeleon.net/encriptar-y-desencriptar-con-rsa-en-java/

Deja un comentario

Diseña un sitio como este con WordPress.com
Comenzar