Encryption/Decryption 通过调整 java 代码在 flutter 中

Encryption/Decryption in flutter by adapting java code

我正在尝试在 flutter 中创建一个应用程序,我的示例代码在 java.

这是示例 java 代码要点 https://gist.github.com/kapiljhajhria/72a22ff75e238878f539f7bb21026208

这是我的 flutter 代码要点 https://gist.github.com/kapiljhajhria/795d1a7c7cf1c76ca8e327bf8b2f51de

这里是我所做工作的简要总结

  1. 生成唯一的会话密钥:AES 随机密钥 256
  2. 使用步骤 1 中的会话密钥加密 JSON 数据
  3. 生成 JSON 数据的 SHA256 哈希值
  4. 使用步骤 1 中的会话密钥加密步骤 3 中生成的哈希值。
  5. 使用 public 密钥加密会话密钥。 Public 密钥作为 certificate.cer 文件提供。我复制了 String 值并将其作为常量添加到 class 中,以使其更易于使用。不确定这是否是最佳方法。
  6. 创建了一个带有 3 个参数的 POST 请求。如java代码所示。我认为我正确地完成了这部分。
  7. 我将获得的响应将使用步骤 1 中的会话密钥进行加密。因此我将不得不解密该响应数据。还没到这一步。

我无法访问发出此请求的服务器。 由于 post 请求是使用网络视图发出的,因此我无法找到一种方法来从我的请求中获取正确的错误。我得到的只是显示“无效请求”的网页

所以我的第一个猜测是我没有正确使用 public 密钥来加密我的会话密钥。 如果那部分是正确的,那么我没有正确加密数据,或者我的加密方法与 java 代码中使用的加密方法不匹配 java 代码。也许我生成的会话密钥不正确。

如有任何帮助,我们将不胜感激。谢谢你。如果您需要我提供任何信息,请告诉我。

看看这个project,这是 Flutter 加密的一个例子,有很好的文档,有 3 种加密类型:

  1. AES 加密
  2. Fernet 加密
  3. Salsa20 加密

我用这个文档作为参考:https://developers.emsigner.com/signer-gateway/api-reference/signing-documents.html

您需要 2 个包:pointycastlex509,并按如下方式导入它们:

import 'package:pointycastle/export.dart';
import 'package:x509/x509.dart';

那么你需要这些辅助函数:

Uint8List generateSessionKey() {
  final r = Random();
  return Uint8List.fromList(List<int>.generate(32, (_) => r.nextInt(256)));
}

RSAPublicKey parseCert(String pemData) {
  final cert = parsePem(pemData).first as X509Certificate;
  final pub = cert.publicKey as RsaPublicKey;
  return RSAPublicKey(pub.modulus, pub.exponent);
}

Uint8List encryptUsingPublicKey(RSAPublicKey key, Uint8List data) {
  final cipher = PKCS1Encoding(RSAEngine())
    ..init(true, PublicKeyParameter<RSAPublicKey>(key));
  return cipher.process(data);
}

Uint8List encryptUsingSessionKey(Uint8List key, Uint8List data) {
  final cipher = PaddedBlockCipher('AES/ECB/PKCS7')
    ..init(true, PaddedBlockCipherParameters(KeyParameter(key), null));
  return cipher.process(data);
}

Uint8List sha256Digest(Uint8List data) {
  return SHA256Digest().process(data);
}

然后您将像这样构建 3 个参数:

  final pem = File('cert2.pem').readAsStringSync();
  final publicKey = parseCert(pem);

  final sessionKey = generateSessionKey();

  final encryptedSessionKey = encryptUsingPublicKey(publicKey, sessionKey);

  final jsonString = json.encode(<String, dynamic>{
    'FileType': 'PDF',
    'SignaturePosition': 'Top-Left',
    'AuthToken': 'some token',
    'File': '',
    'SUrl': 'http://localhost:3000/Success',
    'FUrl': 'http://localhost:3000/Error',
    'CUrl': 'http://localhost:3000/Cancel',
    'ReferenceNumber': 'generate unique reference number',
  });

  final jsonBytes = utf8.encode(jsonString) as Uint8List;

  final encryptedJson = encryptUsingSessionKey(sessionKey, jsonBytes);

  final hash = sha256Digest(jsonBytes);
  final encryptedHash = encryptUsingSessionKey(sessionKey, hash);

  final p1 = base64.encode(encryptedSessionKey);
  final p2 = base64.encode(encryptedJson);
  final p3 = base64.encode(encryptedHash);

但是,我看到的最大问题是您如何执行 POST,因为您想要在网页中,对吗?并且普通的 flutter web 视图不支持初始 post。看起来确实还有另一个包裹。只需搜索 flutter webview post.

顺便说一下,如果你不想使用 pointycastle 注册表,你可以重写 encryptUsingSessionKey 而不是 as:

  final cipher = PaddedBlockCipherImpl(
    PKCS7Padding(),
    ECBBlockCipher(AESEngine()),
  )..init(true, PaddedBlockCipherParameters(KeyParameter(key), null));
  return cipher.process(data);

最后,至少在您了解 Web 视图问题之前,您可以使用 http 来完成 post。但是,让它完成编码参数和设置内容类型的工作,如下:

  final response = await http.post(
    Uri.parse('https://somewhere/V3_0/Index'),
    body: <String, String>{
      'Parameter1': p1,
      'Parameter2': p2,
      'Parameter3': p3,
    },
  );
  print(response.statusCode);
  print(response.body);