Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

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!

share|improve this question
1  
Question: Is this approach reasonable? No, it isn't. You are putting blind trust into advice from strangers, AND rolling your own encryption scheme. This is doubly fraught with danger. –  Deer Hunter Mar 29 '13 at 11:33
3  
@DeerHunter - it isn't really roll your own since he's using established algorithms. You don't want to roll your own algorithms. Using your own arrangement of algorithms is a fairly common and healthy practice as long as you understand what each algorithm provides. –  AJ Henderson Mar 29 '13 at 12:58
    
@AJHenderson because of the prevalence of side channel attacks, and the prevalance of usage mistakes, just using established algorithms is still rolling your own, but granted there are only a few high level opensource alternatives. gpgme, nacl, and keyczar. –  jbtule Mar 29 '13 at 13:08
    
@Jbtule - The reason to not roll your own is because cryptography is hard and relies on large amounts of review to understand limitations. Knowing those limitations and understanding what they mean to a cryptosystem (while still a challenge) is doable and perfectly fine to design your own system to meet your needs. You won't find an out of the box system for every set of needs that comes up in security. The problem is the difficulty in finding weaknesses to the actual encryption mechanisms themselves. –  AJ Henderson Mar 29 '13 at 13:12
    
Like I said granted there are few alternatives, in most cases you have to roll your own usage there's no other option, but the encryption primatives themselves aren't generally exploited these days, it's the usage, padding, verification timing, predictable random numbers, impromper IV uses, improper modes, improper keys, the above code doesn't even include the decryption/verification which is much more perilous for mistakes. The definition for roll your own these days isn't implementing AES or RSA, no one does that, libraries are plentiful, it's implementing the usage of AES or RSA. –  jbtule Mar 29 '13 at 13:34

2 Answers 2

To understand why it makes zero sense to encrypt an IV for CBC mode. You need to understand that each block is encrypted separately and uses the previous ciphertext block as its "IV" so if I magically get the key, but not the IV, I can decrypt everything except the first block of data. So the following makes more sense:

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; }
}

The standard counter to padding oracles (or other chosen plaintext attacks) is authenticated encryption, validating that the EncryptedContent ciphertext is authentic before you operate on it's decrypted data is what's important.

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; }
}

The above is getting messy so you could probably refactor EncryptedData to EncryptedKeys and hold 2 encrypted keys, 1 signature for both, and a fingerprint.

SignData will only do a sha1 hash in the .net api's, since you wanted sha512, do what you are doing with SignHash.

Sign the encrypted keys, not the raw keys, similarly dealing with the decrypted plaintext of the keys before verifying the signature has high potential to leak information of the plaintext.

Your decryption implementation is completely missing from your reasonability question, and it's the most prone area for implementation mistakes that leak data about the plaintext.

That said, I highly suggest you see if you can use a highlevel libary to fit your purposes Keyczar doesn't support a multikey ciphertext about of the box, but it may be possible for you to build off of it to support it or you might be able to rethink a way in which you don't need to encrypt with multiple rsa keys for the same ciphertext.

share|improve this answer
    
Thx for your effort! 1) "so if I magically get the key, but not the IV, I can decrypt everything except the first block of data." Yes, but everything depends on the first block (IV) so you are not able to decrypt any block. 2) So I create a Secret HMAC Key saved it encrypted with each RSA key und create a Hash with this Secret HMAC Key and stored it in ContentMAC? 3) Of course could I choose a highlevel libary, but my intention is to build a own crypto framwork for learning purpose. –  user1776231 Mar 29 '13 at 15:54
    
4) I undestand that a hashed plantext could leak data. But what is wrong to derived a Fingerprint (Hash) from a public rsa key? –  user1776231 Mar 29 '13 at 15:58
2  
@user2104146, 1) That is incorrect, each block only depends on the immediate previous block only. 2) Yes 3) your question states "I want to use a hybrid encryption in my application" and if your goal is learning I suggest Cryptography I. 4) It's not about really as much about hashing the plaintext leaking the data, it's about later when verifying before acting on the plaintext, which thanks to padding that's easiest if you sign the ciphertext. There is nothing wrong with a sha1 fingerprint of the public key, plus it's the public key. –  jbtule Mar 29 '13 at 16:17

The IV is simply to prevent differential analysis between two different messages. It is perfectly fine to be public and in fact needs to be accessible for decryption.

Encrypting for a user with their public key makes no statement about authentication. It isn't a signature, so deniability is irrelevant. There is no signature to attest to the original owner.

There are weaknesses in using the wrong padding for some algorithms. I don't know if there are any that are particularly weak when you are using a more or less random value for your data, but why risk it?

I'm not familiar with the particular library, but according to the the comments I received, SignHash signs a precomputed hash where as SignData computes the hash and does the signature. SignData would likely be better, but I'm not particularly familiar with that exact library, so this answer may be incorrect. Note that signing would make it undeniable as it proves the original ownership. If you don't want to prove original ownership, then signing is unnecessary and counterproductive as an attacker could also sign it and there would be no way to tell if it was genuine or not.

It seems like a pretty run of the mill asymmetric encryption of a symmetric data key. It would be helpful to include the public keys paired with the encrypted AES keys. This will help people lookup the correct key on the keyring to use for decryption. Otherwise they would have to try them all to find the one that their private key unlocks. Don't bother encrypting the IVs either, it's duplicate data and doesn't have to be secure. If a signature is necessary, don't store a collection of signatures, sign the main encrypted payload once for everyone. Signing the keyring is unnecessary as a changed key won't decrypt the payload.

The approach seems reasonable and inline with standard approaches for dealing with it. It's probably not the most solid implementation around, but I also don't see any super glaring issues. You might want to consider looking for an existing library that handles the same thing though since you aren't doing anything unique. (Though it isn't really a role your own issue since you are using established algorithms.)

share|improve this answer
1  
SignHash signs a precomputed hash, SignData computes the hash and signs it. –  jbtule Mar 29 '13 at 13:09
    
@jbtule - thanks for the info. I have updated my answer accordingly. –  AJ Henderson Mar 31 '13 at 23:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.