Contenidos
Para agregar SSL a tus códigos de servidor y cliente, necesitarás configurar correctamente el contexto SSL en ambas partes. Aquí tienes una guía general sobre cómo hacerlo:
Genera los certificados: Necesitarás generar un par de claves pública y privada para el servidor y el cliente. Puedes utilizar herramientas como OpenSSL o Java Keytool para generar los certificados.
Crear certificado con Keytool para el servidor
1 |
keytool -genkey -alias servidor -keyalg RSA -keystore AlmacenSrv -storepass 1234567 |
Exportar certificado .cert con Keytool para el cliente
1 |
keytool -exportcert -alias servidor -keystore AlmacenSrv -storepass 1234567 -file my_certificate.crt |
Crear servidor seguro
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 |
import java.io.DataInputStream import java.io.DataOutputStream import java.io.FileInputStream import java.security.KeyStore import javax.net.ssl.* class Servidor { fun main() { val puerto = 5556 val keyStorePath = "/Users/lamac/IdeaProjects/untitled/AlmacenSrv" val keyStorePassword = "1234567" val keyPassword = "1234567" // Cargar el almacén de claves val keyStore = KeyStore.getInstance("JKS") keyStore.load(FileInputStream(keyStorePath), keyStorePassword.toCharArray()) // Configurar el administrador de claves val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) keyManagerFactory.init(keyStore, keyPassword.toCharArray()) // Configurar el administrador de confianza val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) trustManagerFactory.init(keyStore) // Configurar el contexto SSL val sslContext = SSLContext.getInstance("TLS") sslContext.init(keyManagerFactory.keyManagers, trustManagerFactory.trustManagers, null) // Crear el socket SSL del servidor val sslServerSocketFactory = sslContext.serverSocketFactory val servidorSSL = sslServerSocketFactory.createServerSocket(puerto) as SSLServerSocket var clienteConectado: SSLSocket? = null var flujoEntrada: DataInputStream? = null var flujoSalida: DataOutputStream? = null for (i in 1..2) { println("Esperando al cliente $i") clienteConectado = servidorSSL.accept() as SSLSocket flujoEntrada = DataInputStream(clienteConectado.getInputStream()) // El cliente me envía un mensaje println("Recibiendo del CLIENTE: $i \n\t${flujoEntrada.readUTF()}") flujoSalida = DataOutputStream(clienteConectado.getOutputStream()) // Envío un saludo al cliente flujoSalida.writeUTF("Saludos al cliente del servidor") } // Cerrar streams y sockets flujoEntrada?.close() flujoSalida?.close() clienteConectado?.close() servidorSSL.close() } } fun main(args: Array<String>) { // Iniciar servidor val servidor = Servidor() servidor.main() } |
Crear cliente seguro en Android
Cliente subido en Github: https://github.com/jesusninoc/ClienteAndroidSSL
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 |
package com.example.myapplication import android.content.Context import android.os.AsyncTask import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.example.myapplication.ui.theme.MyApplicationTheme import java.io.DataInputStream import java.io.DataOutputStream import java.security.KeyStore import java.security.cert.CertificateFactory import javax.net.ssl.* class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyApplicationTheme { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { Greeting("Cliente") } } } // Iniciar cliente con el contexto de la aplicación val cliente = Cliente(this) cliente.execute() } } @Composable fun Greeting(name: String, modifier: Modifier = Modifier) { Text( text = "$name!", modifier = modifier ) } class Cliente(private val context: Context) : AsyncTask<Void, Void, Void>() { override fun doInBackground(vararg params: Void?): Void? { val host = "192.168.1.55" val puerto = 5556 val keyStorePassword = "1234567" val keyPassword = "1234567" // Cargar el certificado desde res/raw val certificate = context.resources.openRawResource(R.raw.my_certificate) val certificateFactory = CertificateFactory.getInstance("X.509") val cert = certificateFactory.generateCertificate(certificate) // Configurar el almacén de claves val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()) keyStore.load(null, null) keyStore.setCertificateEntry("certificate", cert) // Configurar el administrador de claves val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) keyManagerFactory.init(keyStore, keyPassword.toCharArray()) // Configurar el administrador de confianza (usamos el mismo almacén de claves para simplificar) val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) trustManagerFactory.init(keyStore) // Configurar el contexto SSL val sslContext = SSLContext.getInstance("TLS") sslContext.init(keyManagerFactory.keyManagers, trustManagerFactory.trustManagers, null) // Crear el socket SSL del cliente val sslSocketFactory = sslContext.socketFactory val cliente = sslSocketFactory.createSocket(host, puerto) as SSLSocket // Creo flujo de salida al servidor val flujoSalida = DataOutputStream(cliente.getOutputStream()) // Envío un saludo al servidor flujoSalida.writeUTF("Saludos al SERVIDOR DESDE EL CLIENTE") // Creo flujo de entrada al servidor val flujoEntrada = DataInputStream(cliente.getInputStream()) // El servidor me envía un mensaje println("Recibiendo del SERVIDOR: \n\t${flujoEntrada.readUTF()}") // Cerrar streams y sockets flujoEntrada.close() flujoSalida.close() cliente.close() return null } } |
Funcionamiento del servidor y del cliente

