Editar: después de un poco de esfuerzo, hice reimplementar una biblioteca SSL eficiente en RAM, que puede ejecutarse en el tipo de cantidad de RAM que se indica a continuación. Tiene muchas más características y flexibilidad que mis creaciones anteriores, y aún así es muy pequeño. Más importante aún, también es OpenSource (licencia MIT). Disfrute: enlace
Es posible implementar un cliente (o servidor) SSL / TLS en aproximadamente 21 kB de código ARM (pulgar), que requieren menos de 20 kB de RAM cuando se ejecuta (*). Sé que se puede hacer porque lo hice (lo siento, no de código abierto). La mayor parte de la complejidad de TLS proviene de su compatibilidad con muchos tipos de algoritmos criptográficos, que se negocian durante el protocolo inicial inicial; Si se concentra en un solo conjunto de algoritmos criptográficos, entonces puede reducir el código a algo que es bastante pequeño. Recomiendo usar TLS 1.2 con el conjunto de cifrado TLS_RSA_WITH_AES_128_CBC_SHA256
: para eso, solo necesitará implementaciones para RSA, AES y SHA-256 (para TLS 1.1 y anteriores, también necesitarías implementaciones para MD5 y SHA-1, lo cual no es difícil pero gastará unos cuantos kBytes de código adicionales). Además, puede hacer que sea sincrónico (en TLS simple, el cliente y el servidor pueden hablar simultáneamente, pero nada los obliga a hacerlo) y omitir la parte de "renegociación de reconocimiento" (el cliente y el servidor realizan un reconocimiento inicial) , pero pueden rehacerlo más tarde durante la conexión).
La parte más complicada de la implementación del protocolo es sobre los certificados. El servidor y el cliente se autentican entre sí usando sus respectivas claves privadas: con RSA, el servidor realiza un descifrado RSA, mientras que el cliente calcula una firma RSA. Esto proporciona autenticación siempre que el cliente y el servidor se conozcan entre sí las claves públicas; por lo tanto, envían sus claves públicas entre sí, envueltas en certificados que son blobs firmados. Un certificado debe validarse antes de su uso, es decir, su firma debe verificarse con respecto a una clave pública conocida a priori (a menudo denominada "CA raíz" o "ancla de confianza"). El cliente no puede usar ciegamente la clave pública que el servidor acaba de enviar, porque permitiría ataques de intermediario.
El análisis y validación del certificado X.509 es un poco complejo (en mi implementación, fue de 6 kB de código, de los 21 kB). Dependiendo de su configuración, puede tener opciones más ligeras; por ejemplo, si puede codificar la clave pública del servidor en el cliente, entonces el cliente simplemente puede usar esa clave y deshacerse del certificado del servidor, que es "solo un blob": no es necesario analizar, no es necesario un certificado, un protocolo muy robusto. También puede definir su propio formato de "certificado". Otra posibilidad es utilizar SRP , que es un mecanismo de intercambio clave en el que ambas partes se autentican entre sí con respecto al conocimiento de un valor secreto compartido (la magia de SRP es que es robusto incluso si el secreto compartido tiene una entropía relativamente baja, por ejemplo, es una contraseña); usa TLS_SRP_SHA_WITH_AES_128_CBC_SHA
.
El punto aquí es que incluso con un protocolo personalizado, no obtendrás algo realmente más ligero que un TLS reducido, al menos si quieres mantenerlo robusto. Y diseñar un protocolo robusto no es fácil en absoluto ; TLS llegó al punto de ser considerado adecuadamente seguro a través de años de sangre y lágrimas. Por lo tanto, es realmente mejor reutilizar TLS que inventar su propio protocolo. Además, esto hace que el código sea mucho más fácil de probar (puede interoperar con implementaciones SSL / TLS existentes).
(*) De los 20 kB de RAM, hay un búfer de 16.5 kB para los "registros" entrantes, porque TLS indica que los registros pueden alcanzar ese tamaño. Si controla tanto el código del cliente como el del servidor, puede organizar un tamaño de registro máximo más pequeño, ahorrando así los requisitos de RAM. La sobrecarga por registro no es mucho (menos de 50 bytes en promedio), por lo que podría usar registros de 4 KB y tener una comunicación eficiente.