TripleDES. Specified padding mode is not valid for this algorithm
Asked Answered
A

2

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;

        }
    }
}
Although answered 23/11, 2016 at 20:2 Comment(7)
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.Orinasal
@rossum: Actually, PKCS#7 makes no assumptions on block size, unlike PKCS#5.Culver
OK, thanks for the correction.Orinasal
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.Waki
@Orinasal Please consider removing incorrect comments.Waki
@Waki 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.Orinasal
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. Using PKCS#5 vs PKCS#7 padding can not solve the padding issue but sugesting it does add confusion.Waki
A
-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;
    }
Although answered 30/1, 2018 at 15:36 Comment(0)
C
-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.

Calve answered 27/1, 2017 at 12:2 Comment(4)
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.Waki
@Waki I had tried using a static IV but it was failing. I still dont know why this worked !!Calve
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.Waki
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.Waki

© 2022 - 2024 — McMap. All rights reserved.