Usar la clase Signature para validar datos autor: Enrique López-Mañas | Snapp Mobile | Octubre de 2020

Cuando se intercambia información, a menudo queremos verificar que el origen de los datos sea correcto. Esto se puede utilizar para garantizar que los clientes adecuados tengan acceso a nuestros recursos.

Por ejemplo, imagine que queremos asegurarnos de que un dispositivo autorizado consulte un archivo con información confidencial de nuestro backend. Una solución inmediata podría ser utilizar el token X-Api en nuestro dispositivo. Escribí anteriormente sobre cómo podemos almacenar tokens de forma segura en Android: idealmente, el token X-Api no debería almacenarse en texto sin formato, porque todo lo que se entrega como texto sin formato en una aplicación de Android puede considerarse de código abierto. Otro punto de inflexión en la historia podría ser una función local que genera un token, que el servidor también comprende.

En realidad, sin embargo, podemos vincular esta autenticación a una fuente específica para proporcionar otra capa de seguridad. Conceptualmente, si quiero acceder al archivo XZY, generaré una verificación apropiada de acceso a este archivo, quizás en combinación con el token X-Api. Si queremos hacer esto en Android, podemos usar la clase Signature para generar una firma.

Tuve que hacer esto recientemente, y en seguridad, a menudo caminamos por el reino del desierto con algunas contribuciones desagradables de StackOverflow, tratando de conectar las piezas. Por lo tanto, el artículo actual: si alguien se beneficia de su contenido, la misión se cumple.

los Firma La clase en Android existe desde su primera versión, aunque tiene varios añadidos a la historia de Android. Lo más importante es que desde el nivel de API 23, tenemos acceso a varios otros algoritmos de cifrado, incluidos SHA512 con RSA / PSS. SHA512withRSA / PSS es probablemente tan seguro como la mayoría de las aplicaciones comerciales.

Este algoritmo crea una firma a partir de una longitud de resumen de 512 bits. PSS significa Sistema de firma probabilística. RSA en sí no es un algoritmo de cifrado, sino una familia de permutaciones que oscurecen el código pero que no son útiles por sí solas. PSS agrega un esquema de cifrado.

Android en realidad no es compatible con PKCS1, por lo que primero debemos generar una clave PKCS. Podemos hacer esto fácilmente usando openssl:

openssl genpkey -out rsakey.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048

Con esta clave ya generada, debemos enviarla al dispositivo. Una opción sería entregar un APK con la clave privada contenida en la carpeta Activos, pero todo lo que viene con el APK de Android puede considerarse de código abierto. La solución sería enviarlo a través de SSL, no es una solución infalible, pero elimina algunos riesgos.

Cuando esté listo, debemos hacer algunos ajustes en la clave. Tenemos que desnudarnos primero INICIAR UNA LLAVE PRIVADA y FIN DE CLAVE PRIVADA porque de lo contrario la clase Signature no funcionará. Cuando lo logremos, podemos proceder al cálculo de la firma:

val signatureSHA256 = Signature.getInstance("SHA256withRSA/PSS")
signatureSHA256.setParameter(PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1))
val privateKey = loadPrivateKey("MY_KEY")
signatureSHA256.initSign(privateKey)
val data: ByteArray = "name_of_the_file".toByteArray()
signatureSHA256.update(data)
var finalSignature = signatureSHA256.sign()

El método para eliminar contenido irrelevante de una clave es el siguiente:

private fun loadPrivateKey(key: String): PrivateKey {
val readString = key.replace("-----BEGIN PRIVATE KEY-----n", "").replace("-----END PRIVATE KEY-----", "")
}

val

encoded = Base64.decode(readString, Base64.DEFAULT)
return KeyFactory.getInstance("RSA")
.generatePrivate(PKCS8EncodedKeySpec(encoded))
}

El siguiente paso sería convertir la firma resultante en código hexadecimal. En Android, podemos hacer esto fácilmente con la extensión Kotlin:

fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }

Ahora estamos listos. Podemos enviar una solicitud a nuestro servidor especificando el archivo al que queremos acceder y la firma asociada a él. El servidor debe realizar el procedimiento opuesto (convertir de hexadecimal a texto y luego usar la verificación de firma). Así es como se vería nuestra solicitud:

El backend ahora debe validar y asegurarse de que los datos estén validados correctamente. Hay algunos cambios en el código anterior; básicamente, esta vez intentamos trabajar con la clave pública y usamos el método verifique los datos)que finalmente verifica que los datos han sido enviados por el cliente correspondiente:

val signatureSHA256 = Signature.getInstance("SHA256withRSA/PSS");
signatureSHA256.setParameter(PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1));
val privateKey = loadPublicKey("MY_KEY")
signatureSHA256.initSign(privateKey);
val data: ByteArray = "name_of_the_file".toByteArray()
signatureSHA256Java.verify(data)
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<pin-set expiration="2018-01-01">
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
<!-- backup pin -->
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
</pin-set>
</domain-config>
</network-security-config>

Android también puede generar un par de claves públicas / privadas en un dispositivo. Por supuesto, esto debe manejarse, pero también agrega otro mundo de posibilidades: si las claves se generan en tiempo real, entonces estamos un poco más seguros. Por supuesto, todavía estamos resolviendo problemas con la transferencia de claves y la seguridad, pero probablemente hayamos eliminado varias amenazas existenciales de la ecuación:

Escribo mis pensamientos sobre la ingeniería de software y la vida en general en la mía. Cuenta de Twitter. Si le gustó o ayudó este artículo, no dude en compartirlo, ♥ y / o dejar un comentario. Esta es una moneda que admite escritores aficionados.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *