leocavalcante / encrypt

🔒 A set of high-level APIs over PointyCastle for two-way cryptography.
BSD 3-Clause "New" or "Revised" License
349 stars 143 forks source link

5.0.2 cannot decrypt data encoded with 5.0.1 #314

Open alextekartik opened 1 year ago

alextekartik commented 1 year ago

I get different results since upgrading to 5.0.2. The following test:

import 'package:encrypt/encrypt.dart';
import 'package:test/test.dart';

String encrypt(String decoded, String password) {
  final key = Key.fromUtf8(password);
  final iv = IV.fromLength(16);
  final encrypter = Encrypter(AES(key));
  return encrypter.encrypt(decoded, iv: iv).base64;
}

String decrypt(String encoded, String password) {
  final key = Key.fromUtf8(password);
  final iv = IV.fromLength(16);
  final encrypter = Encrypter(AES(key));
  return encrypter.decrypt(Encrypted.fromBase64(encoded), iv: iv);
}

void main() {
  test('AES encrypt/decrypt', () {
    var password = r'E4x*$TwbkJC-xK4KGC4zJF9j*Rh&WLgR';
    expect(decrypt('amGhyRRLUIoE59IiEys5Vw==', password), 'test');
  });
}

works fine with 5.0.1 but fails with 5.0.2.

package:pointycastle/paddings/pkcs7.dart 42:7                                  PKCS7Padding.padCount
package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart 112:30  PaddedBlockCipherImpl.doFinal
package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart 74:25   PaddedBlockCipherImpl.process
package:encrypt/src/algorithms/aes.dart 68:22                                  AES.decrypt
package:encrypt/src/encrypter.dart 39:10                                       Encrypter.decryptBytes
package:encrypt/src/encrypter.dart 50:7                                        Encrypter.decrypt
test/aes_test.dart 15:20                                                       decrypt
test/aes_test.dart 21:12                                                       main.<fn>

Invalid argument(s): Invalid or corrupted pad block

Am I using it wrong ? Unfortunately I have some encrypted content that I cannot read anymore. Thanks !

ClevertonZarelli commented 1 year ago

following, i have the same problem after update

aldycool commented 1 year ago

Hi, same here. In the mean time I just use hard-coded version in pubspec.yaml: encrypt: 5.0.1 (without ^).

alessandrorisse commented 1 year ago

Same problem

leocavalcante commented 1 year ago

Can you folks force pointycastle: 3.6.2 to see if it works again, please?

abinvs-2019 commented 1 year ago

Same here.

remsysinc commented 1 year ago

Same, but it's 5.0.2 that is causing the issue. Reverting to 5.0.1 puts things back in order. Interesting gap in updates as 5.0.1 was 2 years ago; 5.0.2 just two days. Great package and hope this gets resolved. Unsure of what (breaking) changes this update provides.

idoamram commented 1 year ago

Same issue

mihaieremia commented 1 year ago

Same issue

heshesh2010 commented 1 year ago

+1

heshesh2010 commented 1 year ago

pointycastle

I overridden to (pointycastle: 3.6.2) and still got same error

hotplato commented 1 year ago

I have the same problem

ivofernandes commented 1 year ago

Same here:

flutter: \^[[38;5;196m[E]\^[[0m zoneGuarded: zoneError ERROR: Invalid argument(s): Invalid or corrupted pad b<…> flutter: #0 PKCS7Padding.padCount (package:pointycastle/paddings/pkcs7.dart:42:7)

1 PaddedBlockCipherImpl.doFinal (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:112:30)

2 PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:74:25)

3 AES.decrypt (package:encrypt/src/algorithms/aes.dart:68:22)

4 Encrypter.decryptBytes (package:encrypt/src/encrypter.dart:39:10)

5 Encrypter.decrypt (package:encrypt/src/encrypter.dart:50:7)

6 EncryptionWrapper.decrypt

leocavalcante commented 1 year ago

Can you guys force pointycastle: 3.2.0? I think that is the one at the previous version.

Constans commented 1 year ago

+1

ClevertonZarelli commented 1 year ago

still with error

leocavalcante commented 1 year ago

The weird thing is that the files on the stacktrace hasn't changed at those spots:

package:encrypt/src/algorithms/aes.dart 68:22
package:encrypt/src/encrypter.dart 39:10
package:encrypt/src/encrypter.dart 50:7

Can you guys spot any differences?

lyskouski commented 1 year ago

The same problem with the latest 5.0.3 version

flutter: [Invalid argument(s): Invalid or corrupted pad block, #0      PKCS7Padding.padCount (package:pointycastle/paddings/pkcs7.dart:42:7)
#1      PaddedBlockCipherImpl.doFinal (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:112:30)
#2      PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:74:25)
#3      AES.decrypt (package:encrypt/src/algorithms/aes.dart:68:22)
#4      Encrypter.decryptBytes (package:encrypt/src/encrypter.dart:39:10)
#5      Encrypter.decrypt (package:encrypt/src/encrypter.dart:50:7)
#6      Encrypter.decrypt64 (package:encrypt/src/encrypter.dart:66:12)
<asynchronous suspension>
leocavalcante commented 1 year ago

The same problem with the latest 5.0.3 version

5.0.3 fixes another bug. This one wasn't spotted yet.

Help wanted.

Constans commented 1 year ago

The weird thing is that what was encrypted with 5.0.2 or 5.0.3 can't be decrypted by the same version of the package (also retroactively - something encrypted with 5.0.1). 5.0.1 can't decode something encoded with 5.0.2 or 5.0.3. The reason is the same mentioned here: https://github.com/leocavalcante/encrypt/issues/314#issuecomment-1723720762. Maybe there is a difference in the Initialization Vector (IV).

leocavalcante commented 1 year ago

That is why I think it something at Pointcastle, there wasn't any significative changes at Encrypt, but people are saying that de downgrade didn't work.

lyskouski commented 1 year ago

Downgrade back to 5.0.1 has helped (with encrypted data by 5.0.3 loss)

leocavalcante commented 1 year ago

I mean: the downgrade of the Pointycastle...

leocavalcante commented 1 year ago

@farukprogrammer do you know if https://github.com/leocavalcante/encrypt/pull/259 does have something with that somehow?

ramvenkat11 commented 1 year ago

+1

ClevertonZarelli commented 1 year ago

Downgrade back to 5.0.1 and clear all data that was encrypted in others version, if you use shared preferences, change the version to automatic clear that. and it back work on this way.

mehdiwaysi commented 1 year ago

I get this error when decrypt data:

Invalid argument(s): Invalid or corrupted pad block

I didn't have this problem before in version 5.0.1. And recently this problem has arisen.

I updated the package to 5.0.2 , 5.0.3 and have the same error

alextekartik commented 1 year ago

In my specific issue, it turns out that replacing:

final iv = IV.fromLength(16);

by

final iv = IV.allZerosOfLength(16);

fixes my test. i.e. the following test works fine using 5.0.3:

import 'package:encrypt/encrypt.dart';
import 'package:test/test.dart';

String aesEncrypt(String decoded, String password) {
  final key = Key.fromUtf8(password);
  // final iv = IV.fromLength(16); (ok in 5.0.1 not in 5.0.3)
  final iv = IV.allZerosOfLength(16);
  final encrypter = Encrypter(AES(key));
  return encrypter.encrypt(decoded, iv: iv).base64;
}

String aesDecrypt(String encoded, String password) {
  final key = Key.fromUtf8(password);
  // final iv = IV.fromLength(16); (ok in 5.0.1 not in 5.0.3)
  final iv = IV.allZerosOfLength(16);
  final encrypter = Encrypter(AES(key));
  return encrypter.decrypt(Encrypted.fromBase64(encoded), iv: iv);
}

void main() {
  test('AES encrypt/decrypt', () {
    var password = r'E4x*$TwbkJC-xK4KGC4zJF9j*Rh&WLgR';
    expect(aesEncrypt('test', password), 'amGhyRRLUIoE59IiEys5Vw==');
    expect(aesDecrypt('amGhyRRLUIoE59IiEys5Vw==', password), 'test');
  });
}

So it seems that the behavior of IV.fromLength() has changed between the 5.0.1 version (filling with 0) and 5.0.3 (filling with random characters.) Maybe this could be considered as a breaking change as it breaks existing code!

EDIT: The following is compatible for both version:

final iv = IV(Uint8List(16));

However reading the comment:

/// The key is ALL ZEROS - NOT CRYPTOGRAPHICALLY SECURE!
IV.allZerosOfLength(int length)

it sounds that it is not fully secure to use this. What is the correct way to encrypt a content that we need to decrypt later then?. Do we need to save also the content of the iv variable to have it for decryption later?

leocavalcante commented 1 year ago

Hi, @alextekartik. Thank you very much for digging into this.

Ideally, the Initialization Vector should be secured as well: https://en.wikipedia.org/wiki/Initialization_vector

After an issue (https://github.com/leocavalcante/encrypt/issues/246) opened by @InnovativeInventor warning about fromLength implementation being insecure (despite its use was never meant to production, only for tests), @timmaffett helped us (and thanks again for that) solving it at https://github.com/leocavalcante/encrypt/pull/266.

@deskangel warned us about this risk at https://github.com/leocavalcante/encrypt/pull/266#issuecomment-1454848466 and people was asking for the changes: https://github.com/leocavalcante/encrypt/issues/295

Meanwhile I haven't been working with Dart/Flutter anymore, I wasn't using this lib and the support was dropping. I had even renewed my PC and there is nothing of a Dart environment installed, but @JimWuerch helped me at https://github.com/leocavalcante/encrypt/issues/310 on how I could automate the package publishing and voilá.

I assume it is all my fault, I thought that was just a matter of sending a new release and haven't looked carefully to check for breaking changes. My bad, not an excuse, but is really hard to maintain OSS already, then alone and in a stack that you don't work for years, is even harder.


Thank you all for you patience. I'd love to hear especially from you guys that use the package, how we can go from there:

alextekartik commented 1 year ago

Thanks for the support, I know maintaining open source project is a pain ! You might want to get other contributors/publishers if you cannot commit to it in the the long term as it seems many people are using it ! So you have to maintain it forever, ha ha.

Hard to change the behavior especially in an API that is shown as an example in the README.md.

The safest behavior would be to add a new IV.randomOfLength() API (or whatever better naming), keeping the existing behavior of fromLength (filling with 0) or even deprecating it...Personally I'm fine with fixing it on my side although it might require going through many projects.

moodstubos commented 1 year ago

hi, @leocavalcante : Thank you very much for you great work!

current state: Encrypted.fromLength(int length) : _bytes = SecureRandom(length).bytes; and Encrypted.fromSecureRandom(int length) : _bytes = SecureRandom(length).bytes;

both (fromLength + from fromSecureRandom) has same implementation. (edit: sorry, not true vor IV) Therefore, I suggest just leaving the fromLength implementation as the previous one (5.0.1) and deprecating it for 5.1.0. Also change docs to use fromSecureRandom.

Therefore, we don't have a breaking change with a change in the second level version slot (5.0.1 to 5.0.2).

fede1295 commented 1 year ago

in my case the issue was caused by pointycastle... with encryption at 5.0.1 and pointycastle at version 3.5.2 everything works correctly

mminhlequang commented 11 months ago

up

vihangel commented 8 months ago

I get different results since upgrading to 5.0.2. The following test:

import 'package:encrypt/encrypt.dart';
import 'package:test/test.dart';

String encrypt(String decoded, String password) {
  final key = Key.fromUtf8(password);
  final iv = IV.fromLength(16);
  final encrypter = Encrypter(AES(key));
  return encrypter.encrypt(decoded, iv: iv).base64;
}

String decrypt(String encoded, String password) {
  final key = Key.fromUtf8(password);
  final iv = IV.fromLength(16);
  final encrypter = Encrypter(AES(key));
  return encrypter.decrypt(Encrypted.fromBase64(encoded), iv: iv);
}

void main() {
  test('AES encrypt/decrypt', () {
    var password = r'E4x*$TwbkJC-xK4KGC4zJF9j*Rh&WLgR';
    expect(decrypt('amGhyRRLUIoE59IiEys5Vw==', password), 'test');
  });
}

works fine with 5.0.1 but fails with 5.0.2.

package:pointycastle/paddings/pkcs7.dart 42:7                                  PKCS7Padding.padCount
package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart 112:30  PaddedBlockCipherImpl.doFinal
package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart 74:25   PaddedBlockCipherImpl.process
package:encrypt/src/algorithms/aes.dart 68:22                                  AES.decrypt
package:encrypt/src/encrypter.dart 39:10                                       Encrypter.decryptBytes
package:encrypt/src/encrypter.dart 50:7                                        Encrypter.decrypt
test/aes_test.dart 15:20                                                       decrypt
test/aes_test.dart 21:12                                                       main.<fn>

Invalid argument(s): Invalid or corrupted pad block

Am I using it wrong ? Unfortunately I have some encrypted content that I cannot read anymore. Thanks !

Im facing same issue

I just changed my yaml to encrypt: 5.0.1

works

alextekartik commented 8 months ago

@vihangel Being stuck on an old version could be a pain. If you change your existing IV.fromLength to IV.allZerosOfLength you should be fine too on future versions - or even IV(Uint8List(length)) if you want to be compatible with old and new versions of encrypt.

Chakib-Temal commented 6 months ago

What does this mean? Are we now stuck in version 5.0.1 or what? @leocavalcante

BheemrajS commented 6 months ago

What does this mean? Are we now stuck in version 5.0.1 or what? @leocavalcante

i had issue when using encrypt version 5.0.2/3 and now i have reverted version to 5.0.1 without "^" prefix as below in pubsepc.xml file. Issue is resolved, encrypt password works. encrypt: 5.0.1

mikezander commented 4 months ago

I'm getting the same error but am not using IV.fromLength. What would be the solution in my case??

  static String decrypt(String s) {
    final e.Key key = e.Key.fromBase64(EnvironmentConfig.encryption_key);
    final e.IV iv = e.IV.fromBase64(EnvironmentConfig.encryption_iv);
    final e.Encrypter encrypter = e.Encrypter(e.AES(key));
    return encrypter.decrypt64(s, iv: iv).toString();
  }

  static String encrypt(String s) {
    final e.Key key = e.Key.fromBase64(EnvironmentConfig.encryption_key);
    final e.IV iv = e.IV.fromBase64(EnvironmentConfig.encryption_iv);
    final e.Encrypter encrypter = e.Encrypter(e.AES(key));
    return encrypter.encrypt(s, iv: iv).base64;
  }