-2

I had a java code and I had to transform it in C# which is as below

Encryption:

 public String encrypt(String value)
    {
        System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
        AesManaged tdes = new AesManaged();
        tdes.Key = UTF8.GetBytes(securityKey);
        tdes.Mode = CipherMode.ECB;
        tdes.Padding = PaddingMode.PKCS7;
        ICryptoTransform crypt = tdes.CreateEncryptor();
        byte[] plain = Encoding.UTF8.GetBytes(value);
        byte[] cipher = crypt.TransformFinalBlock(plain, 0, plain.Length);
        String encryptedText = Convert.ToBase64String(cipher);
        return encryptedText;
    }

Now I am trying to write the reversal process

public String decrypt(String value)
    {                   
        System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
        AesManaged tdes = new AesManaged();
        tdes.Key = UTF8.GetBytes(securityKey);
        tdes.Mode = CipherMode.ECB;
        tdes.Padding = PaddingMode.PKCS7;
        ICryptoTransform crypt = tdes.CreateDecryptor();
        byte[] plain = Encoding.UTF8.GetBytes(value);
        byte[] cipher = crypt.TransformFinalBlock(plain, 0, plain.Length);
        String encryptedText = Convert.ToBase64String(cipher);
        return encryptedText;
    }

But the reversal is not working.

Error: An exception of type

'System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll but was not handled in user code

Additional information: Padding is invalid and cannot be removed.

Stack Trace:

System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) at redis2.Crypto.AESECBPKCS5PaddingEncryptor.decrypt(String value) in e:\TestApplication\Redis\redis2\redis2\Crypto\AESECBPKCS5PaddingEncryptor.cs:line 53 at redis2.WebForm1.Page_Load(Object sender, EventArgs e) in e:\TestApplication\Redis\redis2\redis2\WebForm1.aspx.cs:line 14 at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

update 1

 public String decrypt(String value)
    {                   
        System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
        AesManaged tdes = new AesManaged();
        tdes.Key = UTF8.GetBytes(securityKey);
        tdes.Mode = CipherMode.ECB;
        tdes.Padding = PaddingMode.PKCS7;
        ICryptoTransform crypt = tdes.CreateDecryptor();
       // value = Convert.FromBase64String(value);
        byte[] plain = Convert.FromBase64String(value);
        byte[] cipher = crypt.TransformFinalBlock(plain, 0, plain.Length);
        String encryptedText = Convert.ToBase64String(cipher);
        return encryptedText;
    }
शेखर
  • 17,412
  • 13
  • 61
  • 117
  • 3
    If the ciphertext is base64-encoded, you'll have to decode first, then decrypt. – t.m.adam Nov 29 '18 at 05:55
  • 2
    Possible duplicate of [Padding is invalid and cannot be removed?](https://stackoverflow.com/questions/8583112/padding-is-invalid-and-cannot-be-removed) – Richardissimo Nov 29 '18 at 05:57
  • 1
    @t.m.adam is right. First decode, then decrypt. Poster should include code that is calling these functions for completeness. – TheGreatContini Nov 29 '18 at 06:02
  • @t.m.adam I am not clear about what are you asking for. Can you explain a bit. because i am using base64 to get bytes.`byte[] plain = Encoding.UTF8.GetBytes(value);` – शेखर Nov 29 '18 at 06:05
  • Your `encrypt` method returns the ciphertext as a base64-encoded string. In your `decrypt` method you should first base64-decode this string to bytes, and then decrypt it. `Encoding.UTF8.GetBytes` doesn't base64-decode the string, it just converts it to bytes. – t.m.adam Nov 29 '18 at 06:07
  • @t.m.adam I have changed to `byte[] plain = Convert.FromBase64String(value);` but that giving me wrong output. – शेखर Nov 29 '18 at 07:09
  • 1
    @शेखर - yes, because you fixed one issue but not the other. To transform the plaintext into `byte[]` for encryption, you used UTF8. To transform `byte[]` into ciphertext string, you then used `Base64`. In your decryption routine, you're now correctly undoing the latter of these two transformations to get back the correct `byte[]` but you're still using the wrong encoding to transform the decrypted `byte[]` back into a string. – Damien_The_Unbeliever Nov 29 '18 at 07:16
  • @Damien_The_Unbeliever can you post the answer or comment the correct one. – शेखर Nov 29 '18 at 11:20
  • `UTF8.GetBytes(securityKey)` is always the wrong way to get a key from a string. See Rfc2898DeriveBytes. – H H Dec 02 '18 at 13:36

2 Answers2

3

With encryption and decryption code, it's not uncommon for you to perform at least one other conversion of the data along it's way through the encryption code. When writing the decryption code, you need to make sure you apply the reverse of each transformation in the reverse order.

So, in your encryption code, we have

[string] --UTF8--> [byte[]] --Encrypt--> [byte[]] --Base64--> [string]

With your original decryption code, we have

[string] --UTF8--> [byte[]] --Decrypt--> [byte[]] --Base64--> [string]

But that's not doing the reverse transforms in the reverse order. Lets put them alongside each other with the decryption one reversed:

[string] --UTF8--> [byte[]] --Encrypt--> [byte[]] --Base64--> [string] --|
                                                                         |
[gnirts] <--46esaB-- [[]etyb] <--tpyrceD-- [[]etyb] <--8FTU-- [gnirts] <-|

(The extra arrow at the end shows the transfer of the string by some other code from the return from encrypt to supplying it as a parameter to decrypt).

We can see that we're doing something UTF8 related when we should be doing something to undo Base 64 encoding, and we're doing something Base64 related when we should be doing something UTF8 related.

So the correction is to base 64 decode the passed in string to decrypt and to UTF8 decode the result after decryption:

public String decrypt(String value)
{                   
    System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
    AesManaged tdes = new AesManaged();
    tdes.Key = UTF8.GetBytes(securityKey);
    tdes.Mode = CipherMode.ECB;
    tdes.Padding = PaddingMode.PKCS7;
    ICryptoTransform crypt = tdes.CreateDecryptor();
    byte[] plain = Convert.FromBase64String(value);
    byte[] cipher = crypt.TransformFinalBlock(plain, 0, plain.Length);
    String encryptedText = Encoding.UTF8.GetString(cipher);
    return encryptedText;
}

I'd usually recommend that when people are working with decryption, they start as simple as possible and then build up from there. The simplest thing to have gotten right first here would have been something that accepted a byte[] and returned a byte[] (for both methods) and can successfully round trip a byte array. Then add string encoding support for either the plaintext or the ciphertext but not both. Confirm that round trips. Then add another encoding. A zip layer. etc.

(This is also my recommended strategy for encrypt with language 1, decrypt with language 2. First write methods that can round trip successfully in both languages with all necessary transformations, then do the work of making them interoperate)

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
3

tdes.Key = UTF8.GetBytes(securityKey);

Is always the wrong way to get a key from a string.

  • When you have a password, use Rfc2898DeriveBytes
  • when you need to pass a random binary key, use Convert.FromBase64String()

String encryptedText = Encoding.UTF8.GetString(cipher);

Is the wrong way to transport binary data as text. This won't even round-trip because UTF8 has escape sequences to encode non-ASCII tokens. And you can't break those up.

Use Convert.ToBase64String(byte[])

H H
  • 263,252
  • 30
  • 330
  • 514