首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Dart加密AES/CBC/Dart 5加密

用Dart加密AES/CBC/Dart 5加密
EN

Stack Overflow用户
提问于 2020-09-25 07:22:44
回答 1查看 4.9K关注 0票数 2

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

我知道固定盐和IV根本不推荐。但为了简单起见,为了理解这一问题,我将盐分和四字保持为“000000000000000000000000000000000000000000”;

加密后的散列= "XjxCg0KK0ZDWa4XMFhykIw==";使用的私钥= "Mayur12354673645“

有人能帮我用飞镖解密上面的字符串吗?

JAVA代码

代码语言:javascript
复制
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);
        }
    }

我的Dart密码

代码语言:javascript
复制
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;
  }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-25 12:51:17

可以使用现有的Dart库将二进制转换为十六进制,从而简化代码,反之亦然。PointyCastle还支持(PKCS7)填充,因此不必使用自定义实现,这也减少了代码。在互联网上,您可以找到AES/CBC/PKCS7Padd与PBKDF2结合使用PointyCastle的几种省道实现,例如这里这里

使用尖堡转换包解密的一个可能的Dart实现是(为了简单,没有异常处理):

代码语言:javascript
复制
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);
}

通过发布的测试数据:

代码语言:javascript
复制
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的另一种选择是密码学包,在当前情况下,它甚至允许更紧凑的实现:

代码语言:javascript
复制
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和salt。除此之外,5的迭代次数通常太低。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64059645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档