Eastrall / EntityFrameworkCore.DataEncryption

A plugin for Microsoft.EntityFrameworkCore to add support of encrypted fields using built-in or custom encryption providers.
MIT License
326 stars 54 forks source link

Problem with EF Encryption When You Set *Length Attributes -> Documentation #6

Closed warpcoil closed 1 year ago

warpcoil commented 4 years ago

When you set *Length (i.e. MaxLength and StringLength) attributes the model creator will honour that length as NVARCHAR(X) instead of the original NVARCHAR(MAX).

This is ordinarily optimal except when encrypting more space is used as a result of the encryption process. So a 'hacky' workaround is below.

        /// <summary>
        /// Overrides Model Creation System, We want all fields labelled with [Encrypted] to be encrypted
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
                {
            base.OnModelCreating(modelBuilder);

            modelBuilder.UseEncryption(_provider);

            //Adjust each field that is encrypted to be NVARCHAR(MAX) as opposed to NVARCHAR(50) or whatever
            //We have to allow for encrypted size
            foreach (var property in modelBuilder.Model.GetEntityTypes().SelectMany(t => t.GetProperties()).Where(p => p.ClrType == typeof(string)))
            {
                var memberInfo = property.PropertyInfo ?? (MemberInfo)property.FieldInfo;
                var encryptedAttribute = memberInfo?.GetCustomAttribute<EncryptedAttribute>();
                if (encryptedAttribute == null) continue;
                //Ok so we have an [Encrypted] attribute
                //Convert to nvarchar(max), to ensure all data is not truncated
                property.SetColumnType("NVARCHAR(MAX)");
            }
        }

Now there's some consensus on not mixing View Models with Data Models, which I do understand, but simple app, simple solution, why define twice. Both the server side and client side have the same rules, i.e. max lengths, have a certain format etc etc.

Enables:

        [Encrypted]
        [MinLength(4, ErrorMessage = "Your email address must have at least 4 characters")]
        [MaxLength(75, ErrorMessage = "Your email address cannot exceed 75 characters")]
        [Required(ErrorMessage = "Your email address is required")]
        [DataType(DataType.EmailAddress, ErrorMessage = "Your email address does not conform to a standard email address")]
        public string EmailAddress { get; set; }
Eastrall commented 4 years ago

Hi,

You are correct, if we use the [Encrypted] attribute, it should force to use NVARCHAR(MAX) because as you mentioned, encryption uses more space.

Would you mind opening an issue to include your fix?