I want to use a hybrid encryption in my application, so after reading a lot of lines I ended with this implemantation, please critizie it ;) (I want to stick to .Net)
byte[] aesKey = GetRandomBytes(256); // 256 Bits with RNGCryptoServiceProvider
byte[] aesIV = GetRandomBytes(128); // 128 Bits with RNGCryptoServiceProvider
Question: Should I encrypt the IV, in my understand this would be only secruity trough obscurity and don't add anything to my secruity.
Now I encrypt aesKey and aesIV with each PublicKey (Recipient).
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);
}
Question: If a don't store the Fingerprint, is it deniable?
Question: I read that the wrong padding could be a secruity issue, but what if I encrypt a random aes key?
If an passed 'sign == true' I sign the data with each privateKey (Sender), in normale case one key.
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);
}
}
Question: Is RSACryptoServiceProvider.SignHash the right method? (Or SignData?)
Question: I find different approaches, some want to sign the plain data and other the encrypted. What do yo think?
Now I encrypt the actual data
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();
}
}
At the end I searlize this object and send to 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; }
}
Question: Would you add/remove information?
I saw this chart on http://www.keylength.com/en/compare/
http://i.imgur.com/msHcaIe.png
So I think I should use a 16384 bit RSA key to meet the secruity level of aes 256. This does work with csp = new RSACryptoServiceProvider(16384);
but takes a few minutes.
Question: Is this approach reasonable?
Thanks a lot!