在Java中加密并在dart flutter中解密

Shu*_*ham 3 encryption cryptography aes dart flutter

我正在解密 dart 中用 java 加密的文本。这是用于加密的java代码。

\n
package aes;\n\nimport java.security.InvalidKeyException;\nimport java.security.MessageDigest;\nimport java.util.Arrays;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport javax.crypto.Cipher;\nimport javax.crypto.spec.SecretKeySpec;\n\npublic class Aes {\n\n    public static void main(String[] args) {\n        try {\n\n            String keyString = "1234567890123456";//length of key is 16\n            Cipher desCipher = Cipher.getInstance("AES");\n            byte[] key = keyString.getBytes("UTF-8");\n            MessageDigest sha = MessageDigest.getInstance("SHA-1");\n            key = sha.digest(key);\n            key = Arrays.copyOf(key, 16); // use only first 128 bit\n\n            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");\n            desCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);\n\n            String plainText = "abcd";\n\n            byte[] text = plainText.getBytes("UTF-8");\n            byte[] textencrypted = desCipher.doFinal(text);\n            System.out.println("encrypted: " + new String(textencrypted));\n\n        } catch (Exception ex) {\n            Logger.getLogger(Aes.class.getName()).log(Level.SEVERE, null, ex);\n        }\n    }\n\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

Cipher desCipher = Cipher.getInstance("AES");这里没有定义加密模式。我发现当模式未定义时它使用AES/ECB/PKCS5Padding. 加密期间也不使用 IV。

\n

我正在将 java android 应用程序迁移到 flutter。服务器上的数据使用上述 java 代码进行加密。现在我无法更改服务器中所有正在使用的数据。我必须在 flutter 中解密它才能在 flutter 应用程序中显示数据。

\n

我正在使用encrypt: ^4.1.0包在 dart 中进行解密。

\n
  Encrypted encryptedText = Encrypted.fromUtf8(\'\xc3\x9f\xc3\x88\xc2\xb68)\\\xc5\x93\xc3\xa57\xc2\xa3\');\n  final key = Key.fromUtf8(\'1234567890123456\');\n  final iv = IV.fromLength(16);\n\n  final encrypter = Encrypter(AES(key, mode: AESMode.ecb));\n\n  final decrypted = encrypter.decrypt(encryptedText, iv: iv);\n\n  print(decrypted); \n
Run Code Online (Sandbox Code Playgroud)\n

但这段代码给出错误如下

\n
E/flutter (18070): [ERROR:flutter/lib/ui/ui_dart_state.cc(171)] Unhandled Exception: Invalid argument(s): Input data length must be a multiple of cipher\'s block size\nE/flutter (18070): #0      PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:60:9)\nE/flutter (18070): #1      AES.decrypt (package:encrypt/src/algorithms/aes.dart:55:22)\nE/flutter (18070): #2      Encrypter.decryptBytes (package:encrypt/src/encrypter.dart:25:17)\nE/flutter (18070): #3      Encrypter.decrypt (package:encrypt/src/encrypter.dart:31:17)\nE/flutter (18070): #4      _MyHomePageState.sha1 (package:flutter_decrypt_video/main.dart:196:33)\nE/flutter (18070): #5      _MyHomePageState.build (package:flutter_decrypt_video/main.dart:85:5)\nE/flutter (18070): #6      StatefulElement.build (package:flutter/src/widgets/framework.dart:4681:28)\nE/flutter (18070): #7      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4564:15)\nE/flutter (18070): #8      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4737:11)\nE/flutter (18070): #9      Element.rebuild (package:flutter/src/widgets/framework.dart:4280:5)\nE/flutter (18070): #10     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4543:5)\nE/flutter (18070): #11     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4728:11)\nE/flutter (18070): #12     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4538:5)\nE/flutter (18070): #13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #14     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #15     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)\nE/flutter (18070): #16     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #17     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #18     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4589:16)\nE/flutter (18070): #19     Element.rebuild (package:flutter/src/widgets/framework.dart:4280:5)\nE/flutter (18070): #20     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4543:5)\nE/flutter (18070): #21     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4538:5)\nE/flutter (18070): #22     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #23     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #24     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)\nE/flutter (18070): #25     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #26     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #27     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)\nE/flutter (18070): #28     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #29     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #30     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4589:16)\nE/flutter (18070): #31     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4737:11)\nE/flutter (18070): #32     Element.rebuild (package:flutter/src/widgets/framework.dart:4280:5)\nE/flutter (18070): #33     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4543:5)\nE/flutter (18070): #34     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4728:11)\nE/flutter (18070): #35     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4538:5)\nE/flutter (18070): #36     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #37     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #38     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)\nE/flutter (18070): #39     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #40     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #41     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)\nE/flutter (18070): #42     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)\nE/flutter (18070): #43     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)\nE/flutter (18070): #44     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4589:16)\nE/flutter (18070): #45     StatefulElement.performRebuild (package:flutter/src/widgets/fram\n\n
Run Code Online (Sandbox Code Playgroud)\n

如果有人知道如何做到这一点,请留下您的答案。

\n

在用于加密的java代码中,使用SHA-1哈希算法来获取160位密钥,然后使用前128位进行加密,这可能会导致任何问题吗?

\n

如果有人知道任何其他可以解决我的问题的软件包,请告诉我。

\n

如果有人想要任何进一步的信息,请告诉我。

\n

提前致谢 !!

\n

Top*_*aco 5

在 Java 代码中,使用字符集编码(如 UTF-8)将密文转换为字符串。这通常会损坏数据。这里应该使用像base64这样的二进制到文本的编码。

问题中发布的 Java 代码提供了以下更改:

import java.util.Base64;
...
Cipher desCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
...
String plainText = "The quick brown fox jumps over the lazy dog";
...
System.out.println("encrypted: " + Base64.getEncoder().encodeToString(textencrypted));
...
Run Code Online (Sandbox Code Playgroud)

以下 Base64 编码的密文:

encrypted: Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF
Run Code Online (Sandbox Code Playgroud)

可以使用Pointy Castle包和以下 Dart 代码来解密该密文:

import 'dart:convert';
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/block/aes_fast.dart';
import 'package:pointycastle/block/modes/ecb.dart';
import 'package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart';
import 'package:pointycastle/paddings/pkcs7.dart';
...
Digest sha1 = Digest("SHA-1");
Uint8List key = sha1.process(utf8.encode('1234567890123456')).sublist(0, 16);
Uint8List ciphertext = base64.decode('Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF');
ECBBlockCipher cipher = ECBBlockCipher(AESFastEngine());
PaddedBlockCipher paddedCipher = new PaddedBlockCipherImpl(new PKCS7Padding(), cipher);
PaddedBlockCipherParameters<CipherParameters, CipherParameters> paddingParams = new PaddedBlockCipherParameters(KeyParameter(key), null);
paddedCipher.init(false, paddingParams);
Uint8List plainText = paddedCipher.process(ciphertext);
print(utf8.decode(plainText));
Run Code Online (Sandbox Code Playgroud)

请注意以下几点: ECB 是一种不安全模式。更安全的是 CBC(请参阅此处的 dart 示例)或 GCM,后者允许加密和数据身份验证。此外,使用 SHA-1 从密码派生密钥也是不安全的。这里应该使用可靠的密钥导出函数,例如PBKDF2。

编辑:
将密文转换为具有 UTF-8 等字符集的字符串会损坏数据。你可以在 Stackoverflow 上找到很多帖子,例如这篇文章,它详细解释了这个问题。这意味着如果使用 UTF-8 转换密文,您问题中发布的 Java 代码将无法可靠地工作。

但是,有些字符集(例如 ISO-8859-1)不会损坏数据。服务器上可能使用这样的字符集。这无法从发布的代码中确定,因为在解码期间(即在new String(textencrypted))中没有指定字符集,因此应用了相应平台的默认字符集,请参见此处。因此,要检查这种可能性,您必须确定服务器上使用的默认字符集。
分析使用哪种编码的另一种方法是检查(或发布)用于解密服务器创建的密文的代码。

最可靠的是使用专门将二进制数据转换为字符串的编码,即所谓的二进制到文本编码,例如 Base64,请参阅此处,这就是我在发布的示例中使用 Base64 的原因。


您可以使用以下 Java 代码验证使用 UTF-8 或 ISO-8859-1 转换的效果。上面发布的示例中的数据用作密文:

convertDataWith(StandardCharsets.UTF_8);
convertDataWith(StandardCharsets.ISO_8859_1);
...
private static void convertDataWith(Charset charset) {
    String ciphertextBeforeB64 = "Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF";    // Data from posted example
    byte[] ciphertextBefore = Base64.getDecoder().decode(ciphertextBeforeB64);
    String ciphertextCharset = new String(ciphertextBefore, charset);                                   // Convert to String with specified charset
    byte[] ciphertextAfter = ciphertextCharset.getBytes(charset);                                       // Convert from String with specified charset
    String ciphertextAfterB64 = Base64.getEncoder().encodeToString(ciphertextAfter);
    System.out.println("Ciphertext BEFORE conversion: " + ciphertextBeforeB64);
    System.out.println("Ciphertext AFTER conversion:  " + ciphertextAfterB64);  
}
Run Code Online (Sandbox Code Playgroud)

输出:

import java.util.Base64;
...
Cipher desCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
...
String plainText = "The quick brown fox jumps over the lazy dog";
...
System.out.println("encrypted: " + Base64.getEncoder().encodeToString(textencrypted));
...
Run Code Online (Sandbox Code Playgroud)

如上所述,UTF-8 会损坏数据。