[英]How can i encrypt a string in Dart same like in c# using RijndaelManaged
這是我使用 RijndaelManaged 進行字符串加密的 c# 代碼,我無法像 flutter 中那樣進行加密,我嘗試了很多包。 但沒有結果。 我需要在 flutter 中加密一個字符串,我需要在 c# 中解密
public static string key = Environment.GetEnvironmentVariable("ENCR_KEY");
private const int Keysize = 256;
private const int DerivationIterations = 100;
public string Encrypt(string plainText)
{
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(key, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 128;
symmetricKey.Mode = CipherMode.CBC;
//symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[16];
using (var rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
public string Decrypt(string cipherText)
{
string password = key;
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
var salt = cipherBytes.Take(16).ToArray();
var iv = cipherBytes.Skip(16).Take(16).ToArray();
var encrypted = cipherBytes.Skip(32).ToArray();
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt, 100);
encryptor.Key = pdb.GetBytes(32);
encryptor.Padding = PaddingMode.PKCS7;
encryptor.Mode = CipherMode.CBC;
encryptor.IV = iv;
using (MemoryStream ms = new MemoryStream(encrypted))
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Read))
{
using (var reader = new StreamReader(cs, Encoding.UTF8))
{
return reader.ReadToEnd();
}
}
}
}
}
當我嘗試使用加密密碼在 c# 中解密時。我收到此錯誤消息“填充無效且無法刪除。”
這是我的 Dart 代碼
import 'dart:convert';
import 'package:pointycastle/block/aes_fast.dart';
import 'dart:typed_data';
import 'package:pointycastle/export.dart';
import 'package:pointycastle/key_derivators/pbkdf2.dart';
import 'package:pointycastle/paddings/pkcs7.dart';
import 'package:pointycastle/pointycastle.dart';
const KEY_SIZE = 32; // 32 byte key for AES-256
const ITERATION_COUNT = 2;
const SALT = "XXXXXXXXXXXXXXXXX";
const INITIAL_VECTOR = "ZZZZZZZZZZZZZZZZ";
const PASS_PHRASE = "YYYYYYYYYYYYYYYYYYY";
Future<String> cryptString(String text) async {
String encryptedString = "";
final mStrPassPhrase = toUtf8(PASS_PHRASE);
encryptedString = AesHelperMethod2.encrypt(
mStrPassPhrase,
toUtf8(text),
mode: AesHelperMethod2.CBC_MODE,
);
return encryptedString;
}
Future<String> decryptString(String text) async {
String decryptedString = "";
final mStrPassPhrase = toUtf8(PASS_PHRASE);
decryptedString = AesHelperMethod2.decrypt(mStrPassPhrase, toUtf8(text),
mode: AesHelperMethod2.CBC_MODE);
return decryptedString;
}
///MARK: AesHelper class
class AesHelperMethod2 {
static const CBC_MODE = 'CBC';
static const CFB_MODE = 'CFB';
static Uint8List deriveKey(dynamic password,
{String salt = '',
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);
Pbkdf2Parameters params =
new Pbkdf2Parameters(saltBytes, iterationCount, derivedKeyLength);
KeyDerivator keyDerivator =
new PBKDF2KeyDerivator(new HMac(new SHA1Digest(), 64));
keyDerivator.init(params);
return keyDerivator.process(password);
}
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}) {
String salt = toASCII(SALT);
Uint8List derivedKey = deriveKey(password, salt: salt);
KeyParameter keyParam = new KeyParameter(derivedKey);
BlockCipher aes = new AESFastEngine();
var ivStr = toASCII(INITIAL_VECTOR);
Uint8List iv = createUint8ListFromString(ivStr);
BlockCipher cipher;
ParametersWithIV params = new ParametersWithIV(keyParam, iv);
switch (mode) {
case CBC_MODE:
cipher = new CBCBlockCipher(aes);
break;
case CFB_MODE:
cipher = new CFBBlockCipher(aes, aes.blockSize);
break;
default:
throw new ArgumentError('incorrect value of the "mode" parameter');
break;
}
cipher.init(true, params);
Uint8List textBytes = createUint8ListFromString(plaintext);
Uint8List paddedText = pad(textBytes, aes.blockSize);
Uint8List cipherBytes = _processBlocks(cipher, paddedText);
final enc = base64.encode(cipherBytes);
print("enc : " "$enc");
return base64.encode(cipherBytes);
}
static String decrypt(String password, String ciphertext,
{String mode = CBC_MODE}) {
String salt = toASCII(SALT);
Uint8List derivedKey = deriveKey(password, salt: salt);
KeyParameter keyParam = new KeyParameter(derivedKey);
BlockCipher aes = new AESFastEngine();
var ivStr = toASCII(INITIAL_VECTOR);
Uint8List iv = createUint8ListFromString(ivStr);
Uint8List cipherBytesFromEncode = base64.decode(ciphertext);
Uint8List cipherIvBytes =
new Uint8List(cipherBytesFromEncode.length + iv.length)
..setAll(0, iv)
..setAll(iv.length, cipherBytesFromEncode);
BlockCipher cipher;
ParametersWithIV params = new ParametersWithIV(keyParam, iv);
switch (mode) {
case CBC_MODE:
cipher = new CBCBlockCipher(aes);
break;
case CFB_MODE:
cipher = new CFBBlockCipher(aes, aes.blockSize);
break;
default:
throw new ArgumentError('incorrect value of the "mode" parameter');
break;
}
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);
Uint8List textBytes = unpad(paddedText);
return new String.fromCharCodes(textBytes);
}
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;
}
}
///MARK: HELPERS
Uint8List createUint8ListFromString(String s) {
Uint8List ret = Uint8List.fromList(s.codeUnits);
return ret;
}
String toUtf8(value) {
var encoded = utf8.encode(value);
var decoded = utf8.decode(encoded);
return decoded;
}
String toASCII(value) {
var encoded = ascii.encode(value);
var decoded = ascii.decode(encoded);
return decoded;
}
C# encrypt()
方法執行以下操作:
必須在 Dart 代碼中復制這些功能構建塊:為此,您需要一個生成隨機值的 function。 到目前為止,發布的代碼中沒有這樣的東西。 另外,需要重構用於密鑰推導的deriveKey()
function。 可以封裝在函數中的其他功能包括在 CBC 模式下使用 AES 加密和 PKCS#7 填充以及數據的連接和編碼。
SecureRandom getSecureRandom() {
List<int> seed = List<int>.generate(32, (_) => Random.secure().nextInt(256));
return FortunaRandom()..seed(KeyParameter(Uint8List.fromList(seed)));
}
deriveKey()
方法的重構Uint8List deriveKey(Uint8List salt, Uint8List passphrase){
KeyDerivator derivator = KeyDerivator('SHA-1/HMAC/PBKDF2');
Pbkdf2Parameters params = Pbkdf2Parameters(salt, 100, 256~/8);
derivator.init(params);
return derivator.process(passphrase);
}
Uint8List encryptAesCbcPkcs7(Uint8List plaintext, Uint8List key, Uint8List iv){
CBCBlockCipher cipher = CBCBlockCipher(AESEngine());
ParametersWithIV<KeyParameter> params = ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null> paddingParams = PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(params, null);
PaddedBlockCipherImpl paddingCipher = PaddedBlockCipherImpl(PKCS7Padding(), cipher);
paddingCipher.init(true, paddingParams);
Uint8List ciphertext = paddingCipher.process(plaintext);
return ciphertext;
}
String concatAndEncode(Uint8List salt, Uint8List iv, Uint8List ciphertext){
BytesBuilder saltIvCiphertext = BytesBuilder();
saltIvCiphertext.add(salt);
saltIvCiphertext.add(iv);
saltIvCiphertext.add(ciphertext);
String saltIvCiphertextB64 = base64Encode(saltIvCiphertext.toBytes());
return saltIvCiphertextB64;
}
那么這些功能塊只需要連線:
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:pointycastle/export.dart';
...
Uint8List plaintext = Uint8List.fromList(utf8.encode("The quick brown fox jumps over the lazy dog"));
Uint8List passphrase = Uint8List.fromList(utf8.encode("my passphrase"));
// Generate random 16 bytes salt and random 16 bytes IV
SecureRandom secureRandom = getSecureRandom();
Uint8List salt = secureRandom.nextBytes(16);
Uint8List iv = secureRandom.nextBytes(16);
// Derive 32 bytes key via PBKDF2
Uint8List key = deriveKey(salt, passphrase);
// Encrypt with AES-256/CBC/PKCS#7 padding
Uint8List ciphertext = encryptAesCbcPkcs7(plaintext, key, iv);
// Concat salt|nonce|ciphertext and Base64 encode
String saltIvCiphertextB64 = concatAndEncode(salt, iv, ciphertext);
print(saltIvCiphertextB64); // e.g. 3igL9PVjgWpCTwYHP2GluZ/8lUaNblnGFEjZFDEiGvdnjoR/RkXIEtcPmgsnC4MmsfesGXo8Jls2vnCISoVAkzIZvadxbw5Dq1QddeMPnS0=
用這個 Dart 代碼生成的密文可以用 C# 代碼解密。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.