mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-05-16 15:56:51 +08:00
aes
This commit is contained in:
@@ -319,6 +319,9 @@
|
||||
"nowTimestamp": "Now timestamp",
|
||||
"hosts": "Hosts",
|
||||
"toAddress": "To Address",
|
||||
"encrypt": "Encrypt",
|
||||
"decrypt": "Decrypt",
|
||||
"cipher": "Cipher",
|
||||
|
||||
"appUpdateCheckVersion": "Check for Updates",
|
||||
"appUpdateNotAvailableMsg": "Already Using The Latest Version",
|
||||
|
||||
@@ -318,6 +318,9 @@
|
||||
"nowTimestamp": "当前时间戳(秒)",
|
||||
"hosts": "Hosts 映射",
|
||||
"toAddress": "映射地址",
|
||||
"encrypt": "加密",
|
||||
"decrypt": "解密",
|
||||
"cipher": "加解密",
|
||||
|
||||
"appUpdateCheckVersion": "检查更新",
|
||||
"appUpdateNotAvailableMsg": "已是最新版本",
|
||||
|
||||
@@ -28,22 +28,23 @@ import 'package:proxypin/network/components/manager/rewrite_rule.dart';
|
||||
import 'package:proxypin/network/components/manager/script_manager.dart';
|
||||
import 'package:proxypin/network/http/http.dart';
|
||||
import 'package:proxypin/network/util/logger.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/cert_hash.dart';
|
||||
import 'package:proxypin/ui/component/device.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/encoder.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/js_run.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/qr_code_page.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/regexp.dart';
|
||||
import 'package:proxypin/ui/component/utils.dart';
|
||||
import 'package:proxypin/ui/content/body.dart';
|
||||
import 'package:proxypin/ui/desktop/request/request_editor.dart';
|
||||
import 'package:proxypin/ui/desktop/toolbar/setting/request_rewrite.dart';
|
||||
import 'package:proxypin/ui/desktop/toolbar/setting/script.dart';
|
||||
import 'package:proxypin/ui/toolbox/aes_page.dart';
|
||||
import 'package:proxypin/utils/platform.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import 'toolbox/timestamp.dart';
|
||||
import '../toolbox/cert_hash.dart';
|
||||
import '../toolbox/encoder.dart';
|
||||
import '../toolbox/js_run.dart';
|
||||
import '../toolbox/qr_code_page.dart';
|
||||
import '../toolbox/regexp.dart';
|
||||
import '../toolbox/timestamp.dart';
|
||||
|
||||
bool isMultiWindow = false;
|
||||
|
||||
@@ -100,6 +101,10 @@ Widget multiWindow(int windowId, Map<dynamic, dynamic> argument) {
|
||||
return TimestampPage(windowId: windowId);
|
||||
}
|
||||
|
||||
if (argument['name'] == 'AesPage') {
|
||||
return AesPage();
|
||||
}
|
||||
|
||||
//脚本日志
|
||||
if (argument['name'] == 'ScriptConsoleWidget') {
|
||||
return ScriptConsoleWidget(windowId: windowId);
|
||||
|
||||
@@ -28,7 +28,6 @@ import 'package:proxypin/network/components/manager/rewrite_rule.dart';
|
||||
import 'package:proxypin/network/http/content_type.dart';
|
||||
import 'package:proxypin/network/http/http.dart';
|
||||
import 'package:proxypin/network/util/logger.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/encoder.dart';
|
||||
import 'package:proxypin/ui/component/json/json_viewer.dart';
|
||||
import 'package:proxypin/ui/component/json/theme.dart';
|
||||
import 'package:proxypin/ui/component/multi_window.dart';
|
||||
@@ -41,6 +40,7 @@ import 'package:proxypin/utils/platform.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../component/json/json_text.dart';
|
||||
import '../toolbox/encoder.dart';
|
||||
|
||||
///请求响应的body部分
|
||||
///@Author wanghongen
|
||||
|
||||
@@ -24,7 +24,6 @@ import 'package:proxypin/network/channel/channel_context.dart';
|
||||
import 'package:proxypin/network/http/http.dart';
|
||||
import 'package:proxypin/network/http/websocket.dart';
|
||||
import 'package:proxypin/ui/component/memory_cleanup.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/toolbox.dart';
|
||||
import 'package:proxypin/ui/component/widgets.dart';
|
||||
import 'package:proxypin/ui/configuration.dart';
|
||||
import 'package:proxypin/ui/content/panel.dart';
|
||||
@@ -37,6 +36,7 @@ import 'package:proxypin/utils/listenable_list.dart';
|
||||
|
||||
import '../app_update/app_update_repository.dart';
|
||||
import '../component/split_view.dart';
|
||||
import '../toolbox/toolbox.dart';
|
||||
|
||||
/// @author wanghongen
|
||||
/// 2023/10/8
|
||||
|
||||
@@ -23,7 +23,7 @@ import 'package:proxypin/network/components/manager/request_block_manager.dart';
|
||||
import 'package:proxypin/network/components/manager/request_rewrite_manager.dart';
|
||||
import 'package:proxypin/network/http/http.dart';
|
||||
import 'package:proxypin/storage/histories.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/toolbox.dart';
|
||||
import 'package:proxypin/ui/toolbox/toolbox.dart';
|
||||
import 'package:proxypin/ui/component/utils.dart';
|
||||
import 'package:proxypin/ui/configuration.dart';
|
||||
import 'package:proxypin/ui/mobile/setting/preference.dart';
|
||||
|
||||
@@ -33,7 +33,7 @@ import 'package:proxypin/network/http/http.dart';
|
||||
import 'package:proxypin/network/http/websocket.dart';
|
||||
import 'package:proxypin/network/http/http_client.dart';
|
||||
import 'package:proxypin/ui/component/memory_cleanup.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/toolbox.dart';
|
||||
import 'package:proxypin/ui/toolbox/toolbox.dart';
|
||||
import 'package:proxypin/ui/configuration.dart';
|
||||
import 'package:proxypin/ui/content/panel.dart';
|
||||
import 'package:proxypin/ui/launch/launch.dart';
|
||||
|
||||
222
lib/ui/toolbox/aes_page.dart
Normal file
222
lib/ui/toolbox/aes_page.dart
Normal file
@@ -0,0 +1,222 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_toastr/flutter_toastr.dart';
|
||||
import 'package:proxypin/network/util/logger.dart';
|
||||
|
||||
import '../component/buttons.dart';
|
||||
import '../component/text_field.dart';
|
||||
import '../../utils/aes.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class AesPage extends StatefulWidget {
|
||||
const AesPage({super.key});
|
||||
|
||||
@override
|
||||
State<AesPage> createState() => _AesWidgetState();
|
||||
}
|
||||
|
||||
class _AesWidgetState extends State<AesPage> {
|
||||
final TextEditingController inputController = TextEditingController();
|
||||
final TextEditingController outputController = TextEditingController();
|
||||
final TextEditingController keyController = TextEditingController();
|
||||
final TextEditingController ivController = TextEditingController();
|
||||
|
||||
String selectedMode = 'ECB';
|
||||
String selectedPadding = 'PKCS7';
|
||||
int selectedKeyLength = 128;
|
||||
final List<String> modes = ['ECB', 'CBC'];
|
||||
final List<String> paddingModes = ['PKCS7', 'ZeroPadding'];
|
||||
final List<int> keyLengths = [128, 192, 256];
|
||||
|
||||
void encryptText() {
|
||||
try {
|
||||
final input = Uint8List.fromList(utf8.encode(inputController.text));
|
||||
final encrypted = AesUtils.encrypt(input,
|
||||
key: keyController.text,
|
||||
mode: selectedMode,
|
||||
iv: ivController.text,
|
||||
keyLength: selectedKeyLength,
|
||||
padding: selectedPadding);
|
||||
outputController.text = base64.encode(encrypted);
|
||||
} catch (e) {
|
||||
logger.e("Encryption error: $e");
|
||||
FlutterToastr.show("Encryption failed", context, duration: 3, backgroundColor: Colors.red);
|
||||
}
|
||||
}
|
||||
|
||||
void decryptText() {
|
||||
try {
|
||||
final input = base64.decode(inputController.text);
|
||||
final decrypted = AesUtils.decrypt(input,
|
||||
key: keyController.text,
|
||||
mode: selectedMode,
|
||||
iv: ivController.text,
|
||||
keyLength: selectedKeyLength,
|
||||
padding: selectedPadding);
|
||||
outputController.text = utf8.decode(decrypted);
|
||||
} catch (e) {
|
||||
outputController.text = "";
|
||||
logger.e("Decryption error: $e");
|
||||
FlutterToastr.show("Decryption failed", context, duration: 3, backgroundColor: Colors.red);
|
||||
}
|
||||
}
|
||||
|
||||
AppLocalizations get localizations => AppLocalizations.of(context)!;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text("AES", style: TextStyle(fontSize: 16)), centerTitle: true),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: ListView(children: [
|
||||
const SizedBox(height: 5),
|
||||
SizedBox(
|
||||
height: 150,
|
||||
child: TextField(
|
||||
controller: inputController,
|
||||
maxLines: 8,
|
||||
onTapOutside: (event) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
decoration: decoration(context, label: localizations.inputContent))),
|
||||
const SizedBox(height: 15),
|
||||
Wrap(spacing: 18, runSpacing: 5, crossAxisAlignment: WrapCrossAlignment.center, children: [
|
||||
SizedBox(
|
||||
width: 120,
|
||||
child: Row(children: [
|
||||
Text("Mode"),
|
||||
const SizedBox(width: 15),
|
||||
DropdownButton<String>(
|
||||
value: selectedMode,
|
||||
items: modes.map((mode) {
|
||||
return DropdownMenuItem(value: mode, child: Text(mode));
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedMode = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
])),
|
||||
SizedBox(
|
||||
width: 195,
|
||||
child: Row(children: [
|
||||
Text("Padding"),
|
||||
const SizedBox(width: 15),
|
||||
DropdownButton<String>(
|
||||
value: selectedPadding,
|
||||
items: paddingModes.map((mode) {
|
||||
return DropdownMenuItem(value: mode, child: Text(mode));
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedPadding = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
])),
|
||||
SizedBox(
|
||||
width: 190,
|
||||
child: Row(children: [
|
||||
Text("Key Length"),
|
||||
const SizedBox(width: 15),
|
||||
DropdownButton<int>(
|
||||
value: selectedKeyLength,
|
||||
items: keyLengths.map((length) {
|
||||
return DropdownMenuItem(value: length, child: Text("$length bits"));
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedKeyLength = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
]))
|
||||
]),
|
||||
const SizedBox(height: 15),
|
||||
Wrap(
|
||||
spacing: 18.0, // 主轴方向子组件的间距
|
||||
runSpacing: 10.0, // 交叉轴方向子组件的间距
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 230,
|
||||
child: Row(children: [
|
||||
const SizedBox(width: 25, child: Text("Key")),
|
||||
const SizedBox(width: 15),
|
||||
SizedBox(
|
||||
width: 180,
|
||||
height: 45,
|
||||
child: TextField(
|
||||
controller: keyController,
|
||||
maxLength: 32,
|
||||
onTapOutside: (event) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
style: TextStyle(fontSize: 14),
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
counterText: "",
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 6)))),
|
||||
])),
|
||||
SizedBox(
|
||||
width: 260,
|
||||
child: Row(children: [
|
||||
const SizedBox(width: 25, child: Text("IV")),
|
||||
const SizedBox(width: 15),
|
||||
SizedBox(
|
||||
width: 180,
|
||||
height: 45,
|
||||
child: TextField(
|
||||
controller: ivController,
|
||||
maxLength: 32,
|
||||
onTapOutside: (event) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
style: TextStyle(fontSize: 14),
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
counterText: "",
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 6)))),
|
||||
])),
|
||||
]),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FilledButton(
|
||||
style: ButtonStyle(
|
||||
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)))),
|
||||
onPressed: encryptText,
|
||||
child: Text(localizations.encrypt)),
|
||||
const SizedBox(width: 60),
|
||||
FilledButton(
|
||||
style: ButtonStyle(
|
||||
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)))),
|
||||
onPressed: decryptText,
|
||||
child: Text(localizations.decrypt)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(localizations.output),
|
||||
const SizedBox(height: 5),
|
||||
TextFormField(
|
||||
controller: outputController,
|
||||
readOnly: true,
|
||||
minLines: 5,
|
||||
maxLines: 10,
|
||||
decoration: const InputDecoration(border: OutlineInputBorder()),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FilledButton.icon(
|
||||
style: Buttons.buttonStyle,
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: outputController.text));
|
||||
FlutterToastr.show(localizations.copied, context);
|
||||
},
|
||||
icon: const Icon(Icons.copy),
|
||||
label: Text(localizations.copy),
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,8 @@ import 'package:proxypin/ui/component/buttons.dart';
|
||||
import 'package:proxypin/utils/lang.dart';
|
||||
import 'package:proxypin/utils/platform.dart';
|
||||
|
||||
import '../text_field.dart';
|
||||
import '../component/text_field.dart';
|
||||
|
||||
|
||||
/// Timestamp page
|
||||
/// @author Hongen Wang
|
||||
@@ -5,17 +5,19 @@ import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:proxypin/network/bin/server.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/cert_hash.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/encoder.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/js_run.dart';
|
||||
import 'package:proxypin/ui/component/multi_window.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/qr_code_page.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/regexp.dart';
|
||||
import 'package:proxypin/ui/component/toolbox/timestamp.dart';
|
||||
import 'package:proxypin/ui/mobile/request/request_editor.dart';
|
||||
import 'package:proxypin/ui/toolbox/qr_code_page.dart';
|
||||
import 'package:proxypin/ui/toolbox/regexp.dart';
|
||||
import 'package:proxypin/ui/toolbox/timestamp.dart';
|
||||
import 'package:proxypin/utils/platform.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import 'aes_page.dart';
|
||||
import 'cert_hash.dart';
|
||||
import 'encoder.dart';
|
||||
import 'js_run.dart';
|
||||
|
||||
class Toolbox extends StatefulWidget {
|
||||
final ProxyServer? proxyServer;
|
||||
|
||||
@@ -79,7 +81,7 @@ class _ToolboxState extends State<Toolbox> {
|
||||
]),
|
||||
const Divider(thickness: 0.3),
|
||||
Text(localizations.encode, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
|
||||
Row(
|
||||
Wrap(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => encodeWindow(EncoderType.url, context),
|
||||
@@ -106,11 +108,31 @@ class _ToolboxState extends State<Toolbox> {
|
||||
onTap: () => encodeWindow(EncoderType.md5, context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: const Column(children: [Icon(Icons.enhanced_encryption), SizedBox(height: 3), Text('MD5')]),
|
||||
child: const Column(children: [
|
||||
Icon(IconData(0x23, fontFamily: 'MaterialIcons')), // “#”
|
||||
SizedBox(height: 3),
|
||||
Text('MD5')
|
||||
]),
|
||||
)),
|
||||
],
|
||||
),
|
||||
const Divider(thickness: 0.3),
|
||||
Text("加解密", style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
|
||||
Wrap(children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if (Platforms.isMobile()) {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const AesPage()));
|
||||
return;
|
||||
}
|
||||
MultiWindow.openWindow("AES", "AesPage", size: const Size(700, 660));
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: const Column(children: [Icon(Icons.enhanced_encryption), SizedBox(height: 3), Text('AES')]),
|
||||
)),
|
||||
]),
|
||||
const Divider(thickness: 0.3),
|
||||
Text(localizations.other, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
|
||||
Wrap(
|
||||
children: [
|
||||
47
lib/utils/aes.dart
Normal file
47
lib/utils/aes.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:pointycastle/export.dart';
|
||||
|
||||
class AesUtils {
|
||||
static Uint8List encrypt(Uint8List input,
|
||||
{required String key, required int keyLength, required String mode, required String padding, String? iv}) {
|
||||
return process(input, true, key: key, keyLength: keyLength, mode: mode, padding: padding, iv: iv);
|
||||
}
|
||||
|
||||
static Uint8List decrypt(Uint8List input,
|
||||
{required String key, required int keyLength, required String mode, required String padding, String? iv}) {
|
||||
var data = process(input, false, key: key, keyLength: keyLength, mode: mode, padding: padding, iv: iv);
|
||||
// 移除填充零字节
|
||||
if (padding == 'ZeroPadding') {
|
||||
int lastNonZeroIndex = data.lastIndexWhere((byte) => byte != 0);
|
||||
data = data.sublist(0, lastNonZeroIndex + 1);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static Uint8List process(Uint8List input, bool isEncrypt,
|
||||
{required String key, required int keyLength, required String mode, required String padding, String? iv}) {
|
||||
int keySize = keyLength ~/ 8;
|
||||
|
||||
final aesKey = Uint8List.fromList(utf8.encode(key.padRight(keySize, '0')));
|
||||
final aesIv = mode == 'CBC' ? Uint8List.fromList(utf8.encode(iv!.padRight(keySize, '0'))) : null;
|
||||
|
||||
BlockCipher cipher = BlockCipher(mode == 'CBC' ? 'AES/CBC' : 'AES/ECB');
|
||||
CipherParameters params =
|
||||
aesIv == null ? KeyParameter(aesKey) : ParametersWithIV<KeyParameter>(KeyParameter(aesKey), aesIv);
|
||||
|
||||
if (padding == 'PKCS7') {
|
||||
cipher = PaddedBlockCipherImpl(PKCS7Padding(), cipher);
|
||||
params = PaddedBlockCipherParameters<CipherParameters, CipherParameters>(params, null);
|
||||
}
|
||||
|
||||
// 检查输入长度是否为块大小的整数倍
|
||||
if (input.length % cipher.blockSize != 0 && padding == 'ZeroPadding') {
|
||||
input = Uint8List.fromList(input + Uint8List(cipher.blockSize - (input.length % cipher.blockSize)));
|
||||
}
|
||||
|
||||
cipher.init(isEncrypt, params);
|
||||
return cipher.process(input);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user