Preguntas para el cifrado híbrido. RSA con AES

1

Quiero usar un cifrado híbrido en mi aplicación, así que después de leer muchas líneas terminé con esta implementación, por favor critícalo;) (quiero seguir con .Net)

byte[] aesKey = GetRandomBytes(256); // 256 Bits with RNGCryptoServiceProvider
byte[] aesIV = GetRandomBytes(128); // 128 Bits with RNGCryptoServiceProvider

Pregunta: Si encripto la IV, en mi entender esto sería solo por seguridad en la oscuridad y no agregaría nada a mi seguridad.

Ahora cifro aesKey y aesIV con cada PublicKey (Destinatario).

foreach (RSACryptoServiceProvider key in keys)
{
    var data = new EncryptedData();
    data.Data = key.Encrypt(bytes, true); // with OAEP padding
    data.Fingerprint = CreateFingerprint(key); // SHA1 from the public key
    list.Add(data);
}

Pregunta: Si no almacena la huella digital, ¿es denegable?
Pregunta: He leído que el relleno incorrecto podría ser un problema de seguridad, pero ¿qué sucede si cifro una clave aleatoria?

Si un 'signo == verdadero' pasado, firmo los datos con cada clave privada (Remitente), en el caso normal, una clave.

if (sign)
{
    foreach (RSACryptoServiceProvider key in privateKeys)
    {
        var hash = new SHA512Managed();
        byte[] hashBytes = hash.ComputeHash(data);
        byte[] signHash = key.SignHash(hashBytes, CryptoConfig.MapNameToOID("SHA512"));
        var item = new EncryptedData
            {
                Data = signHash,
                Fingerprint = CreateFingerprint(key)
            };
        encryptedData.Signatures.Add(item);
    }
}

Pregunta: ¿Es RSACryptoServiceProvider.SignHash el método correcto? (O SignData?)
Pregunta: Encuentro diferentes enfoques, algunos quieren firmar los datos simples y otros los cifrados. ¿Qué piensas?

Ahora cifro los datos reales

using (var rijAlg = new RijndaelManaged())
{
    rijAlg.KeySize = 256;
    rijAlg.Key = aesKey;
    rijAlg.IV = aesIV;
    rijAlg.Mode = CipherModeTextMode; // CipherMode.CBC
    rijAlg.Padding = PaddingModeTextMode; // PaddingMode.ISO10126, pad with random data

    using (var stream = new MemoryStream())
    using (ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV))
    using (var encrypt = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
    {
        encrypt.Write(data, 0, data.Length);
        encrypt.FlushFinalBlock();
        return stream.ToArray();
    }
}

Al final, muestro este objeto y lo envío a Bob.

public class EncryptedDataHolder
{
    public IEnumerable<EncryptedData> EncryptedAesKeys { get; set; }

    public IEnumerable<EncryptedData> EncryptedAesIVs { get; set; }

    public IEnumerable<EncryptedData> Signatures { get; set; }

    public byte[] EncryptedContent { get; set; }
}

public class EncryptedData
{
    public byte[] Data { get; set; }
    public byte[] Fingerprint { get; set; }
}

Pregunta: ¿Agregaría o eliminaría información?

Vi este gráfico en enlace
enlace
Así que creo que debería usar una clave RSA de 16384 bits para cumplir con el nivel de seguridad de aes 256. Esto funciona con csp = new RSACryptoServiceProvider(16384); pero toma unos minutos.
Pregunta: ¿Es este enfoque razonable?

¡Muchas gracias!

    
pregunta dh_cgn 29.03.2013 - 11:57
fuente

2 respuestas

2

Para comprender por qué no tiene sentido cifrar un IV para el modo CBC. Debe comprender que cada bloque está cifrado por separado y utiliza el bloque de texto cifrado anterior como su "IV", por lo que si mágicamente recibo la clave, pero no la IV, puedo descifrar todo excepto el primer bloque de datos. Así que lo siguiente tiene más sentido:

public class EncryptedDataHolder
{
    public IEnumerable<EncryptedData> EncryptedAesKeys { get; set; }

    public IEnumerable<EncryptedData> Signatures { get; set; }

    public byte[]  ContentIV { get; set; }

    public byte[] EncryptedContent { get; set; }
}

El contador estándar para rellenar los oráculos (u otros ataques de texto simple elegidos) es cifrado autenticado , validando que el texto cifrado de EncryptedContent es Auténtico antes de operar con sus datos descifrados es lo importante.

public class EncryptedDataHolder
{
    public IEnumerable<EncryptedData> EncryptedAesKeys { get; set; }

    public IEnumerable<EncryptedData> EncryptedHmacKeys { get; set; }

    public IEnumerable<EncryptedData> Signatures { get; set; }

    public byte[]  ContentIV { get; set; }

    public byte[] EncryptedContent { get; set; }

    public byte[]  ContentMAC { get; set; }
}

Lo anterior se está complicando, por lo que probablemente podría refactorizar EncryptedData a EncryptedKeys y mantener 2 claves cifradas, 1 firma para ambas y una huella digital.

SignData solo hará un hash sha1 en los api de .net, ya que querías sha512, haz lo que estás haciendo con SignHash.

Firme las claves cifradas, no las claves sin procesar, de forma similar con el texto simple descifrado de las claves antes de verificar que la firma tiene un alto potencial de fuga de información del texto simple.

Su implementación de descifrado falta completamente en su pregunta de razonabilidad, y es el área más propensa a errores de implementación que filtra datos sobre el texto plano.

Dicho esto, te sugiero encarecidamente que veas si puedes utilizar una biblioteca de alto nivel para que se ajuste a tus propósitos Keyczar no es compatible con un texto cifrado de varias partes del cuadro, pero puede ser posible compilarlo para admitirlo o puede replantearse una manera en la que no necesita cifrar con múltiples rsa claves para el mismo texto cifrado.

    
respondido por el jbtule 29.03.2013 - 15:33
fuente
2

El IV es simplemente para evitar el análisis diferencial entre dos mensajes diferentes. Está perfectamente bien ser público y, de hecho, debe ser accesible para el descifrado.

El cifrado para un usuario con su clave pública no hace ninguna declaración sobre la autenticación. No es una firma, por lo que la negabilidad es irrelevante. No hay ninguna firma que certifique al propietario original.

Hay debilidades en el uso del relleno incorrecto para algunos algoritmos. No sé si hay alguna que sea particularmente débil cuando está utilizando un valor más o menos aleatorio para sus datos, pero ¿por qué arriesgarse?

No estoy familiarizado con la biblioteca en particular, pero de acuerdo con los comentarios que recibí, SignHash firma un hash precomputado donde SignData calcula el hash y hace la firma. SignData probablemente sería mejor, pero no estoy particularmente familiarizado con esa biblioteca exacta, por lo que esta respuesta puede ser incorrecta. Tenga en cuenta que la firma lo haría innegable, ya que demuestra la propiedad original. Si no desea demostrar la propiedad original, la firma es innecesaria y contraproducente, ya que un atacante también podría firmarla y no habría manera de saber si fue genuina o no.

Parece una ejecución bastante simple del cifrado asimétrico de una clave de datos simétrica. Sería útil incluir las claves públicas emparejadas con las claves AES cifradas. Esto ayudará a las personas a buscar la clave correcta en el llavero para usar para el descifrado. De lo contrario, tendrían que probarlos todos para encontrar el que desbloquea su clave privada. No se moleste en cifrar los IVs, son datos duplicados y no tiene que ser seguro. Si es necesaria una firma, no almacene una colección de firmas, firme la carga útil cifrada principal una vez para todos. Firmar el anillo de claves no es necesario ya que una clave modificada no descifra la carga útil.

El enfoque parece razonable y en línea con los enfoques estándar para tratar con él. Probablemente no sea la implementación más sólida, pero tampoco veo ningún problema súper evidente. Es posible que desee considerar buscar una biblioteca existente que maneje lo mismo, ya que no está haciendo nada único. (Aunque en realidad no es un rol su propio problema, ya que está usando algoritmos establecidos).

    
respondido por el AJ Henderson 29.03.2013 - 13:58
fuente

Lea otras preguntas en las etiquetas