6

I have a net core app using core1.1 When migrating a cript/decript module from an old .NET4.6 to net core it just wont work

First TripleDES no longer (it used to) supports 128bit keys and is fixed with 192bit keys, trying to change it causes error.

Second, while trying to decript this string:

/Tk0ydguv3HauCVUWDK3Tr6U8c9BBaaRwtSt5q4/uHg=

TripleDES launches error with PKCS7 Padding saing "Specified padding mode is not valid for this algorithm." Which is strange since ti is the padding it defaults.

My project.json:

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.1.0",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Diagnostics": "1.1.0",
    "Microsoft.AspNetCore.Mvc": "1.0.1",
    "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview2-final",
      "type": "build"
    },
    "Microsoft.AspNetCore.Routing": "1.0.1",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Logging": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
    "Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
    "Microsoft.EntityFrameworkCore.Design": "1.0.0-preview2-final",
    "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.1",
    "Microsoft.AspNetCore.Mvc.WebApiCompatShim": "1.0.1",
    "Microsoft.AspNetCore.Session": "1.0.0",
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
  },

    "tools": {
        "BundlerMinifier.Core": "2.0.238",
        "Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0-preview3-final",
        "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
        "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
    },

  "frameworks": {
    "netcoreapp1.1": {
        "imports": [
            "portable-net461+win8"
        ]
    }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "**/*.cshtml",
      "appsettings.json",
      "web.config"
    ]
  },

  "scripts": {
    "prepublish": [ "bower install", "dotnet bundle" ],
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

My code:

using System;
using System.Security.Cryptography;
using System.Text;
namespace WebApp.Class
{
    public class Md5
    {
        private static readonly byte[] IV = { 240, 3, 45, 29, 0, 76, 173, 59 };

        const int NumCryptokey = 6;
        const int NumExtraClave = 8;
        const int NumsKey = 7;


        public static string Generate(int KeyChars)
        {
            int i_key = 0;
            float Random1 = 0;
            Int16 arrIndex = default(Int16);
            StringBuilder sb = new StringBuilder();
            char RandomLetter;

            string KeyLetters = "abcdefghijklmnopqrstuvwxyz";
            string KeyNumbers = "0123456789";

            char[] LettersArray = null;
            char[] NumbersArray = null;

            LettersArray = KeyLetters.ToCharArray();
            NumbersArray = KeyNumbers.ToCharArray();

            for (i_key = 1; i_key <= KeyChars; i_key++)
            {
                Random random = new Random();
                Random1 = random.Next();

                arrIndex = -1;
                if ((Convert.ToInt32(Random1 * 111)) % 2 == 0)
                {
                    while (arrIndex < 0)
                    {
                        arrIndex = Convert.ToInt16(LettersArray.GetUpperBound(0) * Random1);
                    }
                    RandomLetter = LettersArray[arrIndex];
                    if ((Convert.ToInt32(arrIndex * Random1 * 99)) % 2 != 0)
                    {
                        RandomLetter = LettersArray[arrIndex];
                        RandomLetter = char.ToUpper(RandomLetter);
                    }
                    sb.Append(RandomLetter);
                }
                else
                {
                    while (arrIndex < 0)
                    {
                        arrIndex = Convert.ToInt16(NumbersArray.GetUpperBound(0) * Random1);
                    }
                    sb.Append(NumbersArray[arrIndex]);
                }
            }
            return sb.ToString();
        }

        public static string Encriptar(string serializedQueryString)
        {
            string functionReturnValue = null;
            string sRetorno = null;
            try
            {
                string cryptokey = "";
                string ExtraClave = "";
                string sKey = "";

                cryptokey = Generate(NumCryptokey);
                ExtraClave = Generate(NumExtraClave);
                sKey = Generate(NumsKey);

                byte[] buffer = Encoding.ASCII.GetBytes(serializedQueryString + ExtraClave);
                var des = TripleDES.Create();
                var MD5 = System.Security.Cryptography.MD5.Create();
                des.Key = MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(sKey + cryptokey));
                des.IV = IV;

                sRetorno = cryptokey + ExtraClave + sKey + Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));

                functionReturnValue = sRetorno;
            }
            catch (Exception ex)
            {
                functionReturnValue = "";
            }
            return functionReturnValue;

        }

        public static string Desencriptar(string encryptedQueryString)
        {
            string functionReturnValue = null;
            byte[] buffer = null;
            var DES = System.Security.Cryptography.TripleDES.Create();
            var Md5 = MD5.Create();
            string sRetorno = null;

            string cryptokey = "";
            string ExtraClave = "";
            string sKey = "";

            cryptokey = encryptedQueryString.Substring(0,NumCryptokey);
            ExtraClave = encryptedQueryString.Substring(NumCryptokey, NumExtraClave);
            sKey = encryptedQueryString.Substring(NumCryptokey + NumExtraClave, NumsKey);

            encryptedQueryString = encryptedQueryString.Substring(NumCryptokey + NumExtraClave + NumsKey, encryptedQueryString.Length-(NumCryptokey + NumExtraClave + NumsKey));

            try
            {
                buffer = Convert.FromBase64String(encryptedQueryString);
            byte[] by = new byte[24];
                by = Md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(sKey + cryptokey));
            Array.Resize(ref by, 24);
                DES.Key = by;
                DES.IV = IV;

                sRetorno = Encoding.ASCII.GetString(DES.CreateDecryptor().TransformFinalBlock(buffer, 0, buffer.Length)).Replace(ExtraClave, "");
                functionReturnValue = sRetorno;
            }
            catch (Exception ex)
            {
                functionReturnValue = "";
            }
            return functionReturnValue;

        }
    }
}
  • Try PKCS5 padding instead. Technically PKCS#7 is defined for 128 bit ciphers, while PKCS#5 is for 64 bit ciphers, like DES. Your implementation might be picky. – rossum Nov 23 '16 at 22:01
  • 1
    @rossum: Actually, PKCS#7 makes no assumptions on block size, unlike PKCS#5. – President James K. Polk Nov 23 '16 at 22:13
  • OK, thanks for the correction. – rossum Nov 23 '16 at 23:16
  • 3DES has a 168-bit key (the lsb of each bytes is not used which explanes that the key is 24-bnytes. Some, but not all, implementations will allow 16-byte keys by re-using the first 8-bytes as the last 8-bytes. – zaph Nov 24 '16 at 00:51
  • @rossum Please consider removing incorrect comments. – zaph Nov 24 '16 at 11:42
  • @zaph My suggestion to try PKCS#5 is valid. PKCS#5 is defined for 64 bit ciphers. PKCS#7 is defined for 128 bit ciphers and for other sizes, including 64 bit ciphers. – rossum Nov 24 '16 at 12:11
  • PKCS#7 is defined for for all sizes 1 to 255 bytes which includes 64 bit ciphers, PKCS#5 padding is identical to PKCS#7 padding, except that it has only been defined for block ciphers that use a 64-bit (8 byte) block size, see [PKCS#7](https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7). Using PKCS#5 vs PKCS#7 padding can not solve the padding issue but sugesting it does add confusion. – zaph Nov 25 '16 at 13:24

2 Answers2

-1

Found it!

    public static string Encriptar(string serializedQueryString)
    {
        string functionReturnValue = null;
        string sRetorno = null;
        try
        {
            string cryptokey = "";
            string ExtraClave = "";
            string sKey = "";

            cryptokey = Generate(NumCryptokey);
            ExtraClave = Generate(NumExtraClave);
            sKey = Generate(NumsKey);

            byte[] buffer = Encoding.ASCII.GetBytes(serializedQueryString + ExtraClave);
            var des = TripleDES.Create();
            var Md5 = MD5.Create();

            byte[] by = new byte[24];
            by = Md5.ComputeHash(Encoding.ASCII.GetBytes(sKey + cryptokey));
            Array.Resize(ref by, 24);
            Array.Copy(by, 0, by, 16, 8);
            des.Key = by;
            des.IV = IV;
            //es.Padding = PaddingMode.None;
            sRetorno = cryptokey + ExtraClave + sKey + Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));

            functionReturnValue = sRetorno;

        }
        catch (Exception ex)
        {
            functionReturnValue = "";
        }
        return functionReturnValue;
    }
-2

I faced the same issue in ASP.NET Core. However, I was not specifying any IV.

I just added this line while encrypting as well as decrypting after specifying the key.

DES3.IV = new byte[DES3.BlockSize / 8];

Without this line, i was getting the error as described above.

As per the docs at https://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.iv(v=vs.110).aspx

The IV property is automatically set to a new random value whenever you create a new instance of one of the SymmetricAlgorithm classes or when you manually call the GenerateIV method.

However, I still do not understand why this worked because even i tried giving static values to the IV(like yours in question) & it failed even then.

Abdul Rehman Sayed
  • 6,532
  • 7
  • 45
  • 74
  • Use a random IV, just prefix the encrypted data with the IV for use in decryption, it does not need to not secret. Otherwise identical messages or messages with the same beginning will have the same encrypted data and information will be leaked. Also explaining why this worked makes the answer more useful. – zaph Jan 27 '17 at 13:03
  • @zaph I had tried using a static IV but it was failing. I still dont know why this worked !! – Abdul Rehman Sayed Jan 27 '17 at 14:00
  • If the automatically generated random IV is used it must be retrieved and used for subsequent decryption. One way to handle the IV is to prefix the encrypted data with the IV for use in decryption, it does not need to not secret. – zaph Jan 27 '17 at 14:10
  • It is not acceptable to use a method that is not understood. In this case using a fixed IV fixes one error but creates anothrerror: encryption that is not secure. – zaph Jan 27 '17 at 14:13