[resend without the HTML crap - sorry about that!]

Hi Eric!

Thanks for the thorough review! :)

> On 17 May 2017, at 20:08, Eric Biggers <ebigge...@gmail.com> wrote:
> 
> Hi David, thanks for the update!
> 
> On Wed, May 17, 2017 at 01:21:04PM +0200, David Gstir wrote:
>> From: Daniel Walter <dwal...@sigma-star.at>
>> 
>> fscrypt provides facilities to use different encryption algorithms which
>> are selectable by userspace when setting the encryption policy. Currently,
>> only AES-256-XTS for file contents and AES-256-CBC-CTS for file names are
>> implemented. This is a clear case of kernel offers the mechanism and
>> userspace selects a policy. Similar to what dm-crypt and ecryptfs have.
>> 
>> This patch adds support for using AES-128-CBC for file contents and
>> AES-128-CBC-CTS for file name encryption. To mitigate watermarking
>> attacks, IVs are generated using the ESSIV algorithm. While AES-CBC is
>> actually slightly less secure than AES-XTS from a security point of view,
>> there is more widespread hardware support. Especially low-powered embedded
>> devices with crypto accelerators such as CAAM or CESA support only
>> AES-CBC-128 with an acceptable speed. Using AES-CBC gives us the acceptable
>> performance while still providing a moderate level of security for
>> persistent storage.
> 
> You covered this briefly in an email, but can you include more detail in the
> commit message on the reasoning behind choosing AES-128 instead of AES-256?
> Note that this is independent of the decision of CBC vs. XTS.

Sure, I'll extend the commit message to include that.


> 
>> @@ -129,27 +136,37 @@ static int determine_cipher_type(struct fscrypt_info 
>> *ci, struct inode *inode,
>>                               const char **cipher_str_ret, int *keysize_ret)
>> {
>>      if (S_ISREG(inode->i_mode)) {
>> -            if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) {
>> +            switch (ci->ci_data_mode) {
>> +            case FS_ENCRYPTION_MODE_AES_256_XTS:
>>                      *cipher_str_ret = "xts(aes)";
>>                      *keysize_ret = FS_AES_256_XTS_KEY_SIZE;
>>                      return 0;
>> +            case FS_ENCRYPTION_MODE_AES_128_CBC:
>> +                    *cipher_str_ret = "cbc(aes)";
>> +                    *keysize_ret = FS_AES_128_CBC_KEY_SIZE;
>> +                    return 0;
>> +            default:
>> +                    pr_warn_once("fscrypto: unsupported contents encryption 
>> mode %d for inode %lu\n",
>> +                                 ci->ci_data_mode, inode->i_ino);
>> +                    return -ENOKEY;
>>              }
>> -            pr_warn_once("fscrypto: unsupported contents encryption mode "
>> -                         "%d for inode %lu\n",
>> -                         ci->ci_data_mode, inode->i_ino);
>> -            return -ENOKEY;
>>      }
>> 
>>      if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
>> -            if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
>> +            switch (ci->ci_filename_mode) {
>> +            case FS_ENCRYPTION_MODE_AES_256_CTS:
>>                      *cipher_str_ret = "cts(cbc(aes))";
>>                      *keysize_ret = FS_AES_256_CTS_KEY_SIZE;
>>                      return 0;
>> +            case FS_ENCRYPTION_MODE_AES_128_CTS:
>> +                    *cipher_str_ret = "cts(cbc(aes))";
>> +                    *keysize_ret = FS_AES_128_CTS_KEY_SIZE;
>> +                    return 0;
>> +            default:
>> +                    pr_warn_once("fscrypto: unsupported filenames 
>> encryption mode %d for inode %lu\n",
>> +                                 ci->ci_filename_mode, inode->i_ino);
>> +                    return -ENOKEY;
>>              }
>> -            pr_warn_once("fscrypto: unsupported filenames encryption mode "
>> -                         "%d for inode %lu\n",
>> -                         ci->ci_filename_mode, inode->i_ino);
>> -            return -ENOKEY;
>>      }
> 
> With the added call to fscrypt_valid_enc_modes() earlier, the warnings about
> unsupported encryption modes are no longer reachable.  IMO, the
> fscrypt_valid_enc_modes() check should be moved into this function, a proper
> warning message added for it, and the redundant warnings removed.  Also now 
> that
> there will be more modes I think it would be appropriate to put the algorithm
> names and key sizes in a table, to avoid the ugly switch statements.  

I agree. I'll clean this up.



>> +    int err;
>> +
>> +    /* init hash transform on demand */
>> +    if (unlikely(essiv_hash_tfm == NULL)) {
>> +            mutex_lock(&essiv_hash_lock);
>> +            if (essiv_hash_tfm == NULL) {
>> +                    essiv_hash_tfm = crypto_alloc_shash("sha256", 0, 0);
>> +                    if (IS_ERR(essiv_hash_tfm)) {
>> +                            pr_warn_ratelimited("fscrypt: error allocating 
>> SHA-256 transform: %ld\n",
>> +                                                PTR_ERR(essiv_hash_tfm));
>> +                            err = PTR_ERR(essiv_hash_tfm);
>> +                            essiv_hash_tfm = NULL;
>> +                            mutex_unlock(&essiv_hash_lock);
>> +                            return err;
>> +                    }
>> +            }
>> +            mutex_unlock(&essiv_hash_lock);
>> +    }
> 
> There is a bug here: a thread can set essiv_hash_tfm to an ERR_PTR(), and
> another thread can use it before it's set back to NULL.  

Sorry, I missed that... :-(



>> +    err = crypto_cipher_setkey(essiv_tfm, salt, SHA256_DIGEST_SIZE);
>> +    if (err)
>> +            goto out;
> 
> sizeof(salt) instead of hardcoding SHA256_DIGEST_SIZE.
> 
> I think there should also be a brief comment explaining that the ESSIV cipher
> uses AES-256 so that its key size matches the size of the hash, even though 
> the
> "real" encryption may use AES-128.

Good point!


> 
>> +void fscrypt_essiv_cleanup(void)
>> +{
>> +    crypto_free_shash(essiv_hash_tfm);
>> +    essiv_hash_tfm = NULL;
>> +}
> 
> This is called from fscrypt_destroy(), which is a little weird because
> fscrypt_destroy() is meant to clean up only from "fscrypt_initialize()", which
> only allocates certain things.  I think it should be called from
> "fscrypt_exit()" instead.  Then you could also add the __exit annotation, and
> remove setting essiv_hash_tfm to NULL which would clearly be unnecessary.

fscrypt_destroy() is actually also called from fscrypt_exit(). Thats why I 
chose it,
but changing this fscrypt_exit() seems the cleaner approach. :)

Thanks,
David

Reply via email to