在 Dart 中解密 AES/CBC/PKCS5Padding 加密

2023-12-12

我已经有了java加密代码。现在我想使用我的服务器上的 API。即使在尝试了各种教程和示例代码之后,我也无法成功解密哈希值。

我知道固定盐和静脉注射根本不推荐。但为了简单起见并为了理解问题,我将盐和IV保留为“00000000000000000000000000000000”;

Java 加密后的哈希 = "XjxCg0KK0ZDWa4XMFhykIw=="; 使用的私钥=“Mayur12354673645”

有人可以帮我用 dart 解密上面的字符串吗?

JAVA代码

public String encrypt(String salt, String iv, String passphrase,
                              String plaintext) {
            try {
                SecretKey key = generateKey(salt, passphrase);
                byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, key, iv, plaintext
                        .getBytes("UTF-8"));
                return base64(encrypted);
            } catch (UnsupportedEncodingException e) {
                throw fail(e);
            }
        }
    
        public String decrypt(String salt, String iv, String passphrase,
                              String ciphertext) {
            try {
                SecretKey key = generateKey(salt, passphrase);
                byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv,
                        base64(ciphertext));
                return new String(decrypted, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw fail(e);
            }
        }    
    
    private SecretKey generateKey(String salt, String passphrase) {
                try {
                    SecretKeyFactory factory = SecretKeyFactory
                            .getInstance("PBKDF2WithHmacSHA1");
                    KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt),
                            iterationCount, keySize);
                    SecretKey key = new SecretKeySpec(factory.generateSecret(spec)
                            .getEncoded(), "AES");
                    return key;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }

private byte[] doFinal(int encryptMode, SecretKey key, String iv,
                           byte[] bytes) {
        try {
            cipher.init(encryptMode, key, new IvParameterSpec(hex(iv)));
            return cipher.doFinal(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw fail(e);
        }
    }

我的飞镖代码

import 'package:pointycastle/block/aes_fast.dart';
import 'package:pointycastle/block/modes/cbc.dart';
import 'package:pointycastle/digests/sha1.dart';
import 'package:pointycastle/key_derivators/pbkdf2.dart';
import 'package:pointycastle/macs/hmac.dart';
import 'package:pointycastle/paddings/pkcs7.dart';
import 'package:pointycastle/pointycastle.dart';
import 'dart:convert';
import 'dart:typed_data';
import 'package:convert/convert.dart';
import 'dart:developer';

import 'package:pointycastle/random/fortuna_random.dart';

const KEY_SIZE = 16;
const ITERATION_COUNT = 5;

class EncryptionHandler {
  static const CBC_MODE = 'CBC';

  static Uint8List deriveKey(dynamic password,
      {String salt = '0000000000000000',
      int iterationCount = ITERATION_COUNT,
      int derivedKeyLength = KEY_SIZE}) {
    if (password == null || password.isEmpty) {
      throw new ArgumentError('password must not be empty');
    }

    if (password is String) {
      password = createUint8ListFromString(password);
    }

    Uint8List saltBytes = createUint8ListFromString(salt);
    String hexSalt = formatBytesAsHexString(saltBytes);

    KeyDerivator keyDerivator =
    new PBKDF2KeyDerivator(new HMac(new SHA1Digest(), 64));

    Pbkdf2Parameters params =
        new Pbkdf2Parameters(saltBytes, iterationCount, derivedKeyLength);

    keyDerivator.init(params);

    return keyDerivator.process(password);
  }

  Uint8List createUint8ListFromHexString(String hex) {
    var result = new Uint8List(hex.length ~/ 2);
    for (var i = 0; i < hex.length; i += 2) {
      var num = hex.substring(i, i + 2);
      var byte = int.parse(num, radix: 16);
      result[i ~/ 2] = byte;
    }
    return result;
  }

  static String formatBytesAsHexString(Uint8List bytes) {
    var result = new StringBuffer();
    for (var i = 0; i < bytes.lengthInBytes; i++) {
      var part = bytes[i];
      result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
    }
    return result.toString();
  }

  static Uint8List pad(Uint8List src, int blockSize) {
    var pad = new PKCS7Padding();
    pad.init(null);

    int padLength = blockSize - (src.length % blockSize);
    var out = new Uint8List(src.length + padLength)..setAll(0, src);
    pad.addPadding(out, src.length);

    return out;
  }

  static Uint8List unpad(Uint8List src) {
    var pad = new PKCS7Padding();
    pad.init(null);

    int padLength = pad.padCount(src);
    int len = src.length - padLength;

    return new Uint8List(len)..setRange(0, len, src);
  }

  static String encrypt(String password, String plaintext,
      {String mode = CBC_MODE}) {
    Uint8List derivedKey = deriveKey(password);
    KeyParameter keyParam = new KeyParameter(derivedKey);
    BlockCipher aes = new AESFastEngine();

    var rnd = FortunaRandom();
    rnd.seed(keyParam);
    Uint8List iv = createUint8ListFromString("0000000000000000");

    BlockCipher cipher;
    ParametersWithIV params = new ParametersWithIV(keyParam, iv);
    cipher = new CBCBlockCipher(aes);
    cipher.init(true, params);

    Uint8List textBytes = createUint8ListFromString(plaintext);
    Uint8List paddedText = pad(textBytes, aes.blockSize);
    Uint8List cipherBytes = _processBlocks(cipher, paddedText);
    Uint8List cipherIvBytes = new Uint8List(cipherBytes.length + iv.length)
      ..setAll(0, iv)
      ..setAll(iv.length, cipherBytes);

    return base64.encode(cipherIvBytes);
  }

  static String decrypt(String password, String ciphertext) {
    log('Password: $password');
    Uint8List derivedKey = deriveKey(password);
    log('derivedKey: $derivedKey');
    KeyParameter keyParam = new KeyParameter(derivedKey);
    log('keyParam: $keyParam');
    BlockCipher aes = new AESFastEngine();

    Uint8List cipherIvBytes = base64.decode(ciphertext);
    log('cipherIvBytes: $cipherIvBytes');
    Uint8List iv = createUint8ListFromString("0000000000000000");
    // Uint8List iv = new Uint8List(aes.blockSize)
    //   ..setRange(0, aes.blockSize, cipherIvBytes);
    log('iv: $iv');
    BlockCipher cipher;
    ParametersWithIV params = new ParametersWithIV(keyParam, iv);
    log('params: $params');
    cipher = new CBCBlockCipher(aes);
    log('cipher: $cipher');
    cipher.init(false, params);

    int cipherLen = cipherIvBytes.length - aes.blockSize;
    Uint8List cipherBytes = new Uint8List(cipherLen)
      ..setRange(0, cipherLen, cipherIvBytes, aes.blockSize);
    Uint8List paddedText = _processBlocks(cipher, cipherBytes);
    log('cipher: $paddedText');
    Uint8List textBytes = paddedText;
    // Uint8List textBytes = unpad(paddedText);

    return new String.fromCharCodes(textBytes);
  }

  static Uint8List createUint8ListFromString(String s) {
    var ret = new Uint8List(s.length);
    for (var i = 0; i < s.length; i++) {
      ret[i] = s.codeUnitAt(i);
    }
    return ret;
  }

  static Uint8List _processBlocks(BlockCipher cipher, Uint8List inp) {
    var out = new Uint8List(inp.lengthInBytes);

    for (var offset = 0; offset < inp.lengthInBytes;) {
      var len = cipher.processBlock(inp, offset, out, offset);
      offset += len;
    }

    return out;
  }
}

使用现有的 Dart 库进行转换可以简化代码二进制转十六进制反之亦然。 PointyCastle还支持(PKCS7)填充,因此不需要自定义实现,这也减少了代码。在 Internet 上,您可以找到使用 PointyCastle 的 AES/CBC/PKCS7Padding 与 PBKDF2 组合的几种 dart 实现,例如here and here.

使用 Dart 进行解密的可能实现尖角城堡 and convert包例如(为了简单起见,没有异常处理):

import 'dart:typed_data';
import "package:pointycastle/export.dart";
import 'package:convert/convert.dart';
import 'dart:convert';
...
static Uint8List decrypt(Uint8List ciphertext, Uint8List key, Uint8List iv) {
  CBCBlockCipher cipher = new CBCBlockCipher(new AESFastEngine());
  ParametersWithIV<KeyParameter> params = new ParametersWithIV<KeyParameter>(new KeyParameter(key), iv);
  PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null> paddingParams = new PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(params, null);
  PaddedBlockCipherImpl paddingCipher = new PaddedBlockCipherImpl(new PKCS7Padding(), cipher);
  paddingCipher.init(false, paddingParams);
  return paddingCipher.process(ciphertext);
}

static Uint8List generateKey(Uint8List salt, Uint8List passphrase){
  KeyDerivator derivator = new PBKDF2KeyDerivator(new HMac(new SHA1Digest(), 64));
  Pbkdf2Parameters params = new Pbkdf2Parameters(salt, 5, 16);
  derivator.init(params);
  return derivator.process(passphrase);
}

根据发布的测试数据:

String saltHex = '00000000000000000000000000000000';
String ivHex = '00000000000000000000000000000000';
String passphraseUtf8 = 'Mayur12354673645';
String ciphertextBase64 = "XjxCg0KK0ZDWa4XMFhykIw==";

Uint8List salt = hex.decode(saltHex);
Uint8List passphrase = utf8.encode(passphraseUtf8);
Uint8List key = generateKey(salt, passphrase);

Uint8List ciphertext = base64.decode(ciphertextBase64);
Uint8List iv = hex.decode(ivHex);
Uint8List decrypted = decrypt(ciphertext, key, iv);

print(utf8.decode(decrypted)); // This is working

密文可以解密为:这是工作.

PointyCastle 的替代方案是密码学包,在当前情况下允许更紧凑的实现:

import 'package:cryptography/cryptography.dart';
import 'package:convert/convert.dart';
import 'dart:convert';
import 'dart:typed_data';
...
static Uint8List decrypt(Uint8List ciphertext, Uint8List key, Uint8List iv) {
  SecretKey secretKey = new SecretKey(key);
  Nonce nonce = new Nonce(iv);
  Uint8List decrypted = aesCbc.decryptSync(ciphertext, secretKey: secretKey, nonce: nonce);
  return decrypted;
}

static Uint8List generateKey(Uint8List salt, Uint8List passphrase){
  Pbkdf2 pbkdf2 = Pbkdf2(macAlgorithm: new Hmac(sha1), iterations: 5, bits: 128);
  return pbkdf2.deriveBitsSync(passphrase, nonce: Nonce(salt));
}

请注意,在实践中,IV 和盐必须为每个加密随机生成(您已经在问题中提到过)。除此之外,5 次迭代计数通常太低了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Dart 中解密 AES/CBC/PKCS5Padding 加密 的相关文章

  • Flutter Web 应用程序无法在移动浏览器上运行。在手机浏览器上运行flutter代码出现错误如何调试?

    flutter web 应用程序在调试和发布模式下在桌面 chrome 和 safari 浏览器上运行良好 但是 它不适用于调试和发布模式下的移动浏览器 我将发布模式文件上传到服务器上 并尝试使用 URL 访问该网站 但有一个页面无法正常工
  • 如何检索带有元数据标记的函数

    看下面的代码片段 import dart mirrors class meta final String data const meta this data meta Tag doSomething gt print You have to
  • 您可以通过 Dart 编辑器将编译器标志传递给 dart2js

    我想运行 no minify 构建 但不是从终端运行 我可以通过 Dart Editor IDE 本身来完成此操作吗 在 运行 gt 管理启动 下 您可以创建一个新的 Dart2js 启动并传入您想要的任何编译器标志
  • 加密用户数据自动登录第三方系统

    我发现自己的情况是 网站上有一组用户 他们都存储了用户名和密码 这些用户名和密码允许他们通过 SOAP 自动访问第三方服务 这个想法是 每个用户只需要登录主站点即可访问多个服务 并使用每个服务各自存储的用户信息 我觉得这些数据在存储时应该在
  • Java AES 加盐加密

    好吧 事实证明我在加密 解密方面很糟糕 我只是不明白 我怎样才能让Java加密String message1 hello world with String salt mySalt 使用AES加密 加密后我该如何解密 如果您有时间提供最基本
  • Flutter:热重载后被发送回初始页面

    我在用颤振模块将我的应用程序分离到某个模块中 一切看起来都很好 直到我注意到每次执行热重载时 我的应用程序都会自动跳回到登录页面哪个 也是最初的 这是我的设置 class AppWidget extends StatelessWidget
  • 有没有办法将加密的脚本插入 SQL Server 数据库?

    我的公司认为我们编写的数据库脚本是我们知识产权的一部分 在新版本中 我们为用户提供了由两部分组成的设置 桌面应用程序 一个可执行文件 它包含了初始化 更新数据库的复杂性 RedGate SQL Packager 我知道一旦脚本存在我就可以加
  • Flutter:后台中的 SVG 图像抛出错误

    我必须将 SVG 图像保留在背景中并将文本保留在顶部 当我保留 Flutter SVG 包中的 SVG 图像时 出现了这样的错误 I flutter 24437 Unsupported operation Could not resolve
  • Flutter Firebase Cloud函数无法调用

    当我尝试从 Flutter 调用可调用函数时 在使用 Firebase Cloud Functions 时遇到错误 flutter caught generic exception flutter PlatformException fun
  • PHP 中的 MD5 替代方案? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何在flutter中使用API​​调用嵌套的json数据?

    我的 JSON 看起来像这样 Info c type id 1 cleaning type A Cleaning c type id 2 cleaning type B Cleaning c type id 3 cleaning type
  • 扩展 AppCompatActivity 与扩展 flutterActivity

    为了https flutter dev docs development platform integration platform channels tab android channel java tab step 3 add an a
  • 如何使 Flutter 应用字体大小独立于设备设置?

    我需要使我的整个应用程序独立于设备的字体大小设置 我发现我可以设置textScaleFactor 1 0手动为每个文本视图 对于一些文本小部件来说 这是一个很好的解决方案 但对于具有数十个文本小部件的大型应用程序来说 这并不好 首先 我必须
  • 客户端和服务器之间的安全连接

    我正在开发一个服务器组件 它将为嵌入式客户端的请求提供服务 这也在我的控制之下 现在一切都是测试版 安全性是这样的 客户端通过 https 发送用户名 密码 服务器返回访问令牌 客户端使用自定义标头中的访问令牌通过 http 发出进一步请求
  • 使用命令行对文件夹进行GPG加密和解密[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 gpg 命令行 Gnupg 的手册页包含用于加密和解密文件的命令 这是使用 gpg 加密 解密文件的标准命令 gpg encrypt re
  • 重建父级时调用子级 init 方法 - flutter

    据我了解和颤振的工作机制 有状态的小部件方法仅在小部件树中第一次构建时被调用一次 并且每次其状态更改或父级重建时都会调用构建方法方法 bottomNavigationBar BottomNavigationBar items BottomN
  • 这些加密算法有什么区别?

    两者有什么区别MCRYPT RIJNDAEL 128 MCRYPT RIJNDAEL 256 MCRYPT BLOWFISH等等 哪一种最适合网络数据传输 Rijandel 是 AES 的另一个名称 AES 是当前的 一个好的标准 算法 数
  • just_audio 无法在 ios flutter 上工作未处理的异常:(-11800)操作无法完成

    我正在尝试从它自己的存储库运行 just audio 示例项目https github com ryanheise just audio tree master just audio example https github com rya
  • 在 Android 中使用 AES 加密的最佳实践是什么?

    我为什么问这个问题 我知道人们对 AES 加密存在很多疑问 即使对于 Android 也是如此 如果您在网络上搜索 会发现很多代码片段 但在每个页面上 在每个 Stack Overflow 问题中 我都发现了另一个具有重大差异的实现 所以我
  • 加密json数据

    如何加密从客户端到服务器来回传输的 JSON 数据 当我使用firebug时 我可以看到所有数据 内容在result d 我正在使用 ASP NET 3 5 和 C 我们的管理员已将网站设置为使用 https 但我仍然可以发送 POST 请

随机推荐