logotipo

Encriptación: seguridad adicional con .Net



Descripción general

La preocupación por la privacidad de la información y cómo proteger nuestros sistemas y comunicaciones de accesos no autorizados nos está obligando poco a poco a agregar medidas de protección adicionales frente a amenazas cada vez más generalizadas.

[TOC] Tabla de Contenidos



↑↑↑

Encriptación: seguridad adicional con .Net

En un análisis de vulnerabilidades, aparte de los conocidos, temidos, y a veces sobrevalorados “hackers”, poco a poco hemos ido detectando un nuevo tipo de amenazas, y son los propios usuarios del sistema, que conforme van aumentando su formación en las nuevas tecnologías, utilizan las redes corporativas para acceder a información desprotegida.

En la mayoría de las ocasiones, una buena configuración de red o de usuarios y permisos debería mantener a salvo la información, pero con demasiada frecuencia las contraseñas de otros usuarios son de dominio casi público y no se cambian con la frecuencia necesaria. Más preocupante es que el enemigo sea el administrador de la red o tener el servicio de mantenimiento contratado a terceros con una rotación de personal alta.

Una de las contramedidas más eficaces para garantizar la privacidad de información almacenada en nuestro ordenador, es el propio cifrado de disco que nos ofrece Windows. Pero si nuestra clave es conocida por otro usuario o no bloqueamos el ordenador cada vez que nos levantamos de la mesa podemos estar dejando nuestra información de nuevo al descubierto, ya que aunque la información “está cifrada” entre los distintos usuarios, la mayoría de las veces el asalto no proviene de la red o sótanos oscuros, si no de los propios empleados, que aprovechan cualquier descuido para acceder al PC desprotegido.

Si trabajamos con un portátil, el riesgo aumenta considerablemente, cualquier persona con el suficiente interés en acceder a nuestra información sabe que es mucho más fácil robárnoslo que intentar complicadas técnicas de asalto a costa de horas de sueño

Distinguiendo tres tipos de ataque a un sistema de información consideramos ataques por:

Frente a estas situaciones, podemos dotar a nuestras aplicaciones de diferentes mecanismos de cifrado para cada una de las situaciones de uso previstas, diferenciando, de manera muy general, los tres tipos de cifrado conocidos en:

Ya que en las referencias bibliográficas no he encontrado aún ejemplos útiles de cifrado en .Net, y que, en la mayoría de las ocasiones la documentación disponible en la MSDN es demasiado escueta, el objetivo de este artículo es hacer una pequeña introducción a los objetos de cifrado más significativos en .Net, y cómo utilizarlos en cada caso de la manera adecuada con ejemplos concretos de implementación.



↑↑↑

Cifrado unidireccional

Las funciones HASH o resumen se basan en realizar un cálculo que devuelve un valor de longitud fija sobre el texto que deseamos cifrar.

Este cifrado no es reversible, y normalmente se utiliza para almacenar claves de usuario (al realizar la verificación de identidad, se calcula el valor HASH de la contraseña introducida, y si coincide con el HASH de la almacenada, se considera correcta). La gran ventaja de un cifrado HASH es que accediendo, por ejemplo a la tabla de usuario/contraseña almacenada en un directorio la información no es comprometedora (Fig 1)

Tabla de usuario/clave sin cifrado HASH

Usuario

Contraseña

Celso

3d789dc

Ricardo

89ejenS7

. . .

 

Tabla de usuario/clave con cifrado HASH

Usuario

Contraseña

Celso

F15269BE645CD0B9455178A0880DB24D2C6941B

Ricardo

F04D9DAAE05B10DBD093513419F066D17099C268

. . .

 

También podemos agregar un nivel de seguridad a nuestras bases de datos con este cifrado unidireccional. Incluyendo una tabla maestra de nombre-HASH también protegeremos la información, aunque no es nada que no nos resuelvan los identificadores largos de SQL Server (y resulta más eficiente)

En .Net disponemos, dentro del espacio de nombres System.security.Cryptography disponemos de varias versiones del SHA para cifrados unidireccionales.

Dependiendo de la seguridad y del rendimiento que necesitemos (cuanta mayor sea la longitud de cifrado es más seguro, pero tarda más en calcularse), consideramos

SHA1, SHA256, SHA384 y SHA512

Un ejemplo de una implementación de SHA sería

Public  Function  encrypt512(ByVal  message As  String ) As  String 
    Dim  data() As  Byte  = System.Text.Encoding.ASCII.GetBytes(message)
    Dim  result() As  Byte 
    Dim  shaM As  New  System.Security.Cryptography.SHA512Managed
    result = shaM.ComputeHash(data)
    Dim  encrypted As  String  = System.Text.Encoding.ASCII.GetString(result)
    Return  encrypted
End  Function  

Con las siguientes consideraciones:



↑↑↑

Cifrado reversible simétrico o de clave privada

En este tipo de cifrado, disponemos de una sola clave que sirve para cifrar y descifrar. Está especialmente indicado para cifrados en los que no hemos de compartir la información, por ejemplo, cifrar documentos confidenciales de mi portátil para que si lo pierdo, nadie excepto yo pueda devolver los archivos a texto “claro”.

Incorpora dos ventajas, la primera, que el cifrado del texto añade “autenticidad” a nuestro mensaje, ya que, cualquier transformación (ataque por modificación) en la cadena de bytes que lo compone nos impedirá revertir el cifrado.

Por otro lado, frente a las suplantaciones de identidad, podremos saber que cualquier mensaje que recibamos ha sido cifrado, con seguridad, por alguien con el que hemos acordado la clave de cifrado.

El inconveniente para este tipo de cifrado es, definitivamente, cómo hacer llegar al destinatario por canales inseguros una información tan crítica como la clave de cifrado (aparte de que no sabemos dónde la almacenará)

Como decíamos antes, la fortaleza de estos cifrados está limitada a la capacidad que tengamos para almacenar nuestra clave (que puede ir desde los 16 a los 32 caracteres) de manera segura.

Esta tarea no es trivial, ya que una clave de 16 caracteres aleatorios siempre acabará apuntada en un papel, en una agenda,…

Por otro lado, si guardamos cifrada la clave, ¿donde almacenamos la clave de cifrado para descifrar la clave original? Desde luego, en el código del programa o en el registro de Windows, no.

Existe una opción en .Net consistente en pedirle a Windows que nos la guarde cifrada:

Public  sub  guardarClave(clave as  string ) 
    ‘Cifra la clave y la guarda en 
    ‘C:\Documents And Settings\<nombre usuario>\Application data\emskey
    Settings.saveEncrypted(“EMSKEY”,clave)
End  Sub  

Para recuperarla

Public  function  recuperarClave(clave as  string ) as  string 
    Return  Settings.LoadEncrypted(“EMSKEY”)
End  Sub  

Sin embargo, por encriptada que esté, el programa accede a ella, de manera que si alguien accede a nuestro ordenador y ejecuta el programa, tendrá acceso a la clave y a los datos.

Si protegemos el programa con una clave, será tan seguro como la clave que introduzca el usuario, volviendo al punto de partida.



↑↑↑

Almacenes externos de clave

La solución mejor, basándonos en los niveles de seguridad, es almacenar la clave en un dispositivo externo, con un doble beneficio:

Por un lado, el usuario ya no tiene que recordarla (incluso ni que saberla), sólo tiene que conectar el dispositivo.

Por otro lado, garantizamos que es el propietario de la clave el que accede a los datos, ya que nadie excepto él tendrá el dispositivo con la clave (salvo que no la olvide conectada al ordenador, claro)

Lógicamente, es deseable que este dispositivo no sea una llave de memoria USB convencional, ya que cualquiera podría extraer la información fácilmente.

En este aspecto, destacamos los siguientes dispositivos de almacenamiento:

En cualquier caso, recomendamos tener como referencia la web de Aladdin (www.aladdin.com ) para obtener información de estos elementos de seguridad.

Dentro de la implementación de cifrado simétrico, destacamos el cifrado 3DES y Rijndael (también conocido como AES), con longitud de clave de cifrado variable.

Ambos son sistemas de cifrado en bloque con una implementación sencilla y excelente velocidad de cálculo, y aunque nos pongan al máximo la CPU, proporcionarán una buena fortaleza en el cifrado (lo suficiente para que desista cualquiera que no disponga de varias supercomputadoras durante varios años)

Para realizar nuestra implementación necesitaremos dos argumentos, la clave de cifrado y el vector de inicialización del algoritmo (o IV, de Inicialization Vector).

Lógicamente, ambos deben ser iguales al cifrar y al descifrar, lo cual no es un problema trivial como veremos en los comentarios del siguiente segmento de código

Imports  System
Imports  System.IO
Imports  System.Text
Imports  System.Security.Cryptography

‘ Genera un vector de inicialización para 3DES a partir de la clave de encriptacion

Public  function  generateIV(key as  byte ()) As  byte ()
    Dim  slt(0) As  Byte  ‘Inicializamos con un byte  a 0 para 
    ‘garantizar que el cifrado será reversible. Es posible
    ‘utilizar otros valores, pero darán vectores de inicializacion diferentes 
    ‘para cada inicializacion
    Dim  sKey As  string =System.Text.Encoding.ASCII.String (key)
    Dim  pdb As  New  PasswordDeriveBytes(key, slt)
    return  pdb.GetBytes(IVlength)
End  Property  

Una vez tengamos la función generateIV, podemos encriptar y desencriptar con 3DES

Public  Function  encode(ByVal  inBytes As  Byte (), encodingKey As  Byte ()) As  Byte ()
    Dim  DES As  New  TripleDESCryptoServiceProvider
    Dim  xIV as  Byte ()=generateIV(encodingKey)
    Dim  encryptor As  ICryptoTransform = DES.CreateEncryptor(encodingKey, xIV)
    Try 
        Dim  msEncrypt As  New  MemoryStream
        Dim  csEncrypt As  New  CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
        Dim  toEncrypt() As  Byte 
        toEncrypt = bytes
        csEncrypt.Write(toEncrypt, 0, toEncrypt.Length)
        csEncrypt.FlushFinalBlock()
        Dim  encoded As  Byte () = msEncrypt.ToArray()
        Return  encoded
    Catch  ex As  Exception
        Return  Nothing 
    End  Try 
End  Function  
Public  Function  decode(ByVal  bytes As  Byte (), encodingKey As  Byte ()) As  Byte ()
    Dim  DES As  New  TripleDESCryptoServiceProvider
    Dim  xIV as  Byte ()=generateIV(encodingKey)
    Dim  decryptor As  ICryptoTransform = DES.CreateDecryptor(encodingKey, xIV)
    Try 
        Dim  msDecrypt As  New  MemoryStream(bytes)
        Dim  csDecrypt As  New  CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
        Dim  fromEncrypt() As  Byte 
        fromEncrypt = New  Byte (bytes.Length) {}
        csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length)
        Return  fromEncrypt
    Catch  ex As  Exception
        Return  Nothing 
    End  Try 
End  Function  

Implementando estas funciones en una clase, podremos realizar fácilmente rápidas encriptaciones de datos, sin olvidar que el algoritmo utilizado no nos permitirá enviar la información encriptada a otro usuario sin tener que revelar (y comprometer) nuestra clave.

Rijndael, más conocido como AES, incorpora una longitud de clave mayor (32 bytes), por lo que su resistencia es también mayor. Su implementación es extremadamente similar a ésta manteniendo este esquema general, ya que TripleDESCryptoServiceProvider y RijndaelManaged implementan igualmente el método CreateDecryptor, siendo necesario únicamente cambiar las declaraciones de la primera línea de cada funcion (encode y decode)



↑↑↑

Cifrado asimétrico o de clave pública

El cifrado asimétrico (RSA) nació como solución al problema del intercambio de claves necesario para los cifrados reversibles.

En este tipo de cifrado, existe un directorio de claves públicas (o claves para cifrar), a las que cualquiera puede tener acceso. La ventaja es que esto no supone una vulnerabilidad, ya que con esta clave sólo podemos cifrar.

El propietario de la clave pública tiene a su vez una clave privada, que es la que utiliza para descifrar la información (por otro lado, volvemos al viejo problema de almacenar la clave).

Sólo nos presenta tres inconvenientes, más o menos graves:

Como solución a las limitaciones de RSA se plantes el uso de la envoltura digital



↑↑↑

Envoltura digital

Dadas las limitaciones de, por un lado, el cifrado de clave privada y por otro, el de clave pública, parece que no tenemos una buena solución para intercambiar información de manera segura.

Sin embargo, analizando las ventajas y los inconvenientes de cada método:

Cifrado simétrico

Ventajas Velocidad
Fortaleza de cifrado
Inconvenientes No aptos para intercambio de información, ya que no podemos asegurar la seguridad del canal de envío
Algoritmos 3DES
Rijndael (AES)

Cifrado asimétrico

Ventajas Clave pública para cifrado y clave privada para descifrado
Inconvenientes Velocidad de encriptación lenta
Sólo podemos cifrar 512 bytes como máximo
Algoritmos RSA

Llegamos a la conclusión siguiente, que es lo que se ha llamado “envoltura digital”:

Dadas las ventajas y los inconvenientes de cada método, haremos lo siguiente:

  1. cifrar la información con un algoritmo simétrico, es más rápido y puede cifrar cualquier longitud de bytes
  2. Enviar el archivo cifrado al destinatario por un lado, y por el otro, utilizar RSA para, conociendo la clave pública del destinatario, enviarle cifrada la contraseña del algoritmo simétrico.

Una vez que sabemos cómo realizar el intercambio de información, veamos cómo implementar el RSA con .Net.

Primero tendremos que implementar una función que nos genere, a partir del algoritmo RSA, una clave privada que deberemos guardar externamente y de la manera más segura posible.

Public  Function  createRSA() As  String 
    Dim  rsa As  New  System.Security.Cryptography.RSACryptoServiceProvider(2048)
    ‘Genera una instancia del algoritmo de cifrado RSA de 2048 bytes y la exporta a
    ‘formato XML. 
    Dim  tempString As  String  = rsa.ToXmlString(True )
    rsa.Clear()
    Return  tempString
End  Function  

¿Para qué hemos hecho esto? Es más o menos sencillo, esta función nos ha exportado la clave privada del RSA en formato XML. A partir de esta clave almacenada, podremos invocar el algoritmo RSA para que nos descifre una cadena de bytes cifrada con la clave pública.

Para recuperar la clave pública sólo tenemos que pasar como argumento la privada (strPrivateKey) en nuestro código

Function  getPublicKey(ByVal  strPrivatekey As  String ) As  String 
    Dim  rsa As  New  System.Security.Cryptography.RSACryptoServiceProvider
    ‘ Mandamos reconstruir el RSA original a partir de la clave privada
    rsa.FromXmlString(strPrivatekey)
    Return  rsa.ToXmlString(False )
End  Function  

También podemos optar por la opción "Todo en uno"

Public  Function  createRSA_Pair() As  String ()
    Dim  rsa As  New  System.Security.Cryptography.RSACryptoServiceProvider(2048)
    'Genera una instancia del algoritmo de cifrado RSA de 2048 bytes y la exporta a 
    'formato XML. 
    Dim  publicKey As  String  = rsa.ToXmlString(False )
    Dim  privateKey As  String  = rsa.ToXmlString(True ) 
    Dim  RSApair As  String ()={privateKey, publicKey}
    rsa.Clear()
    Return  RSApair
End  Function  

Es importante destacar que, en la llamada al método ToXmlString podemos mandar un booleano si será

Ahora sólo tendremos que enviar a quien desea enviarnos un archivo cifrado nuestra clave pública de RSA, o bien mantener un directorio con la información de todos los usuarios publicada.

Para cifrar una secuencia de bytes, a partir de la clave pública

Function  Encrypt(ByVal  bPlain As  Byte (), ByVal  publicKey As  String ) As  Byte ()
    'Si bPlain tiene más bytes del número permitido por el tamaño del 
    'generado, dará un error en tiempo de ejecucion 
    Dim  rsa As  New  System.Security.Cryptography.RSACryptoServiceProvider
    rsa.FromXmlString(publicKey)
    Dim  bCypher As  Byte () = rsa.Encrypt(bPlain, False )
    Return  bCypher
End  Function  

Para descifrar la secuencia de bytes, recuperaremos nuestra clave privada y la pasaremos como parámetro

Function  Decrypt(ByVal  bCyphered As  Byte (), ByVal  privateKey As  String ) As  Byte ()
    Try 
        Dim  rsa As  New  System.Security.Cryptography.RSACryptoServiceProvider
        rsa.FromXmlString(privateKey)
        Dim  bPlain As  Byte () = rsa.Decrypt(bCyphered, False )
        Return  bPlain
    Catch  ex As  System.Exception
        Return  Nothing 
    End  Try 
End  Function  



↑↑↑

Firma digital de la información

En otras ocasiones la información no tiene porqué estar cifrada, pero sí es necesario que el destinatario tenga la certeza de que le ha llegado sin alteraciones.

Para eso utilizaremos la firma digital de la información, que podemos considerar como un resumen o cadena de caracteres asociada de manera única a un texto o conjunto de bytes.

Quiere esto decir que, si alteramos tan sólo un byte o carácter de la información, ésta producirá un resumen (HASH) totalmente distinto, por lo que podemos:

Con lo que agregamos integridad a nuestra información.

Adicionalmente, al firmarse cada documento con una clave distinta, podemos asociar a un documento y a una firma a la clave pública con la que se generó, agregando entonces autenticidad al mensaje.

El proceso para realizar una firma digital con .Net es sencillo, primero creamos una función para generar los pares de clave DSA (Digital Signature Algorithm), luego sólo hace falta reconstruir una implementación de DSA a partir de las clave privada y un cifrado HASH posterior con SHA

Public  Function  generateDSA() As  String ()
    Dim  DSA As  New  System.Security.Cryptography.DSACryptoServiceProvider(512)
    '512 determina la longitud de la clave de encriptación, admite hasta 1024 en 
    'incrementos de 64, pero ya conocemos el compromiso entre rendimiento y 
    'seguridad 
    Dim  publicKey As  String  = DSA.ToXmlString(False )
    Dim  privateKey As  String  = DSA.ToXmlString(True )
    Dim  DSAparams As  String () = {privateKey, publicKey}
    Return  DSAparams
End  Function  

Como siempre, deberemos tener sumo cuidado con donde almacenamos la clave privada de DSA, ya que cualquiera que la conozca podrá firmar los documentos como si fuéramos nosotros.

Public  Function  signBytes(ByVal  b As  Byte (), privateDSA As  string ) As  Byte ()
    ' Devuelve true si la firma coincide con el contenido en bytes de b 
    Dim  DSA As  New  System.Security.Cryptography.DSACryptoServiceProvider
    DSA.FromXmlString(privateDSA)
    Dim  signature As  New  System.Security.Cryptography.DSASignatureFormatter(privateDSA)
    signature.SetHashAlgorithm("SHA1" )
    Dim  SHA1 As  New  System.Security.Cryptography.SHA1Managed
    Dim  bHASH As  Byte () = SHA1.ComputeHash(b)
    Return  bHASH
End  Function  

Con esta función obtendremos el resumen HASH de la firma, que enviaremos al destinatario junto con la información que debe ser verificada. No olvidemos, de manera parecida a cuando trabajábamos con RSA mandar la clave pública de nuestro DSA.

Publicando un directorio de usuario-clave pública podremos obtener la autenticidad del mensaje.

Por otro lado, cuando recibamos la información podemos verificarla con la función verifySignture, según describimos a continuación

Public  Function  verifySignature(ByVal  originalBytes As  Byte (), publicDSA As  String ) As  bolean
    Dim  DSA As  New  System.Security.Cryptography.DSACryptoServiceProvider
    Dim  DSAbytes(DSAmaxBytes) As  Byte 
    DSA.FromXmlString(publicDSA)
    Dim  signature As  New  System.Security.Cryptography.DSASignatureDeformatter(DSA)
    signature.SetHashAlgorithm("SHA1" )
    Dim  SHA1 As  New  System.Security.Cryptography.SHA1Managed
    Dim  bHASH As  Byte () = SHA1.ComputeHash(originalBytes)
    Return  signature.VerifySignature(bHASH, bSignature)
End  Function  

Existen otros múltiples objetos para el cifrado en System.Security.Cryptography, pero para empezar y familiarizarnos es suficiente con conocer éstos, ya que nos permitirá resolver casi cualquier problema basado en las tendencias actuales en criptografía.


↑↑↑

A.2.Enlaces

[Grupo de documentos]
[Índice general del Documento]
[Home]
[Imprimir el Documento]

↑↑↑

A.3.Información del documento

Título
Encriptación: seguridad adicional con .Net
Autor
Celso Barrutia Navarrete
[http://www.criptoplex.com/]
Director fr soluciones de desarrollo y encriptación
Contenido del documento
La preocupación por la privacidad de la información y cómo proteger nuestros sistemas y comunicaciones de accesos no autorizados nos está obligando poco a poco a agregar medidas de protección adicionales frente a amenazas cada vez más generalizadas.
Tabla de contenidos
[Encriptación: seguridad adicional con .Net ],[Cifrado unidireccional ],[Cifrado reversible simétrico o de clave privada ],[Almacenes externos de clave ],[Cifrado asimétrico o de clave pública ],[Envoltura digital ],[Firma digital de la información ],[Referencia Bibliográfica ],[Autor ]
Publicador
Fechas
Fecha Creación
2007-08-23T00:00:00 [jueves, 23 de agosto de 2007 a las 0:00:00 horas]
Fecha Publicación
2007-08-23T00:00:00 [jueves, 23 de agosto de 2007 a las 0:00:00 horas]
Naturaleza del recurso
Text
IMT (Internet Media Type)
application/xhtml+xml
Juego de caracteres)
ISO 8859-1
Referencia Bibliográfica
Referencia bibliográfica del documento ORIGINAL
Autor<br /> Celso Barrutia Navarrete
Director fr soluciones de desarrollo y encriptación
www.criptoplex.com
Publicado Revista MSCoder Num 4 - 2007
Idioma
es-ES [es = Español] [ES = España]
Copyright
Texto con los derechos
Publicado Revista MSCoder Num 4 - 2007

↑↑↑

© 1.997- 2.007 - La Güeb de Joaquín
Certifico que ésta página está realizada con electrones totalmente reciclables
  Ésta página es española   La Güeb de Joaquín Valid HTML 4.01! Valid XHTML 1.0 Strict Valid CSS! Icono de conformidad con el Nivel Triple-A, de las Directrices de Accesibilidad para el Contenido Web 1.0 del W3C-WAI Creative Commons License