From 78d1925ef5e76e211be8413cd273b0d97a5fc986 Mon Sep 17 00:00:00 2001
From: Falcon <12919280+falconfly@user.noreply.gitee.com>
Date: Fri, 24 Oct 2025 09:54:44 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=A1=86=E6=9E=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 358 ++++++++++++++++++++
PrivateBox.sln | 25 ++
PrivateBox/App.config | 6 +
PrivateBox/AppConfig.cs | 22 ++
PrivateBox/DataContext/DbContext.cs | 34 ++
PrivateBox/DataContext/UserKeys.cs | 12 +
PrivateBox/EncryptionService.cs | 150 ++++++++
PrivateBox/MainForm.Designer.cs | 195 +++++++++++
PrivateBox/MainForm.cs | 22 ++
PrivateBox/MainForm.resx | 151 +++++++++
PrivateBox/PrivateBox.csproj | 31 ++
PrivateBox/Program.cs | 36 ++
PrivateBox/Properties/Resources.Designer.cs | 63 ++++
PrivateBox/Properties/Resources.resx | 120 +++++++
14 files changed, 1225 insertions(+)
create mode 100644 .gitignore
create mode 100644 PrivateBox.sln
create mode 100644 PrivateBox/App.config
create mode 100644 PrivateBox/AppConfig.cs
create mode 100644 PrivateBox/DataContext/DbContext.cs
create mode 100644 PrivateBox/DataContext/UserKeys.cs
create mode 100644 PrivateBox/EncryptionService.cs
create mode 100644 PrivateBox/MainForm.Designer.cs
create mode 100644 PrivateBox/MainForm.cs
create mode 100644 PrivateBox/MainForm.resx
create mode 100644 PrivateBox/PrivateBox.csproj
create mode 100644 PrivateBox/Program.cs
create mode 100644 PrivateBox/Properties/Resources.Designer.cs
create mode 100644 PrivateBox/Properties/Resources.resx
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7e42ad8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,358 @@
+# ---> VisualStudio
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*[.json, .xml, .info]
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# ԿͻĿ
+/src/ClientApp/
+/src/ApiService/Local.db
diff --git a/PrivateBox.sln b/PrivateBox.sln
new file mode 100644
index 0000000..908b2d5
--- /dev/null
+++ b/PrivateBox.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.6.33829.357
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrivateBox", "PrivateBox\PrivateBox.csproj", "{CE1A4FB9-53F4-49C8-B22B-232A673093EB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CE1A4FB9-53F4-49C8-B22B-232A673093EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CE1A4FB9-53F4-49C8-B22B-232A673093EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CE1A4FB9-53F4-49C8-B22B-232A673093EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CE1A4FB9-53F4-49C8-B22B-232A673093EB}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {AC9BD483-D25D-4702-901B-F0F5357C601B}
+ EndGlobalSection
+EndGlobal
diff --git a/PrivateBox/App.config b/PrivateBox/App.config
new file mode 100644
index 0000000..544cd51
--- /dev/null
+++ b/PrivateBox/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PrivateBox/AppConfig.cs b/PrivateBox/AppConfig.cs
new file mode 100644
index 0000000..01fde87
--- /dev/null
+++ b/PrivateBox/AppConfig.cs
@@ -0,0 +1,22 @@
+using System.Configuration;
+
+namespace PrivateBox
+{
+ ///
+ /// 应用配置
+ ///
+ public class AppConfig
+ {
+ ///
+ /// 获取配置值
+ ///
+ /// 配置的键
+ /// 配置值,默认string.Empty
+ public string GetValue(string key) => ConfigurationManager.AppSettings[key] ?? string.Empty;
+
+ ///
+ /// sqliteFile名
+ ///
+ public string SqliteFileName => GetValue("sqliteFile") ?? "";
+ }
+}
diff --git a/PrivateBox/DataContext/DbContext.cs b/PrivateBox/DataContext/DbContext.cs
new file mode 100644
index 0000000..a805fd9
--- /dev/null
+++ b/PrivateBox/DataContext/DbContext.cs
@@ -0,0 +1,34 @@
+using Microsoft.Extensions.DependencyInjection;
+using SqlSugar;
+using System.Runtime.CompilerServices;
+
+namespace PrivateBox
+{
+ ///
+ /// 数据库上下文
+ ///
+ public class DbContext:SqlSugarClient
+ {
+ public AppConfig Config { get; init; }
+
+ public DbContext(IServiceProvider provider,AppConfig config) : base(new ConnectionConfig {
+ DbType = DbType.Sqlite,
+ ConnectionString = config.SqliteFileName,
+ IsAutoCloseConnection = false,
+
+ }) {
+ this.Config = config;
+ }
+
+ ///
+ /// 初始化数据库
+ ///
+ public void DbInit() {
+ this.CodeFirst.SetStringDefaultLength(200);
+ //db.CodeFirst.InitTables();
+ //db.CodeFirst.InitTables();
+ //db.CodeFirst.InitTables();
+
+ }
+ }
+}
diff --git a/PrivateBox/DataContext/UserKeys.cs b/PrivateBox/DataContext/UserKeys.cs
new file mode 100644
index 0000000..d250449
--- /dev/null
+++ b/PrivateBox/DataContext/UserKeys.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PrivateBox.DataContext
+{
+ internal class UserKeys
+ {
+ }
+}
diff --git a/PrivateBox/EncryptionService.cs b/PrivateBox/EncryptionService.cs
new file mode 100644
index 0000000..b889929
--- /dev/null
+++ b/PrivateBox/EncryptionService.cs
@@ -0,0 +1,150 @@
+using System.Security.Cryptography;
+
+///
+/// 加密解密服务接口
+///
+public interface IEncryptionService
+{
+ ///
+ /// 加密字符串
+ ///
+ /// 原始字符串
+ /// 加密密钥(任意长度)
+ /// 加密后的Base64字符串(包含盐值,格式:[加密数据][盐值])
+ string Encrypt(string plainText,string key);
+
+ ///
+ /// 解密字符串
+ ///
+ /// 加密的Base64字符串(包含盐值)
+ /// 解密密钥(与加密密钥相同)
+ /// 解密后的原始字符串
+ string Decrypt(string cipherText,string key);
+}
+
+
+///
+/// AES加密解密服务实现(动态盐值+密钥派生)
+///
+public class AesEncryptionService:IEncryptionService
+{
+ // 配置参数(可通过依赖注入从配置文件读取)
+ private const int SaltSize = 16; // 盐值长度(16字节,推荐值)
+ private const int KeySize = 16; // 派生密钥长度(16字节 = AES-128)
+ private const int Iterations = 10000; // 密钥派生迭代次数(平衡安全性和性能)
+ private static readonly HashAlgorithmName HashAlgorithm = HashAlgorithmName.SHA256;
+
+ public string Encrypt(string plainText,string key) {
+ // 验证输入
+ if(string.IsNullOrEmpty(plainText))
+ throw new ArgumentException("原始字符串不能为空",nameof(plainText));
+ if(string.IsNullOrEmpty(key))
+ throw new ArgumentException("密钥不能为空",nameof(key));
+
+ // 1. 随机生成盐值(.NET 7+ 安全随机数生成)
+ byte[] salt = RandomNumberGenerator.GetBytes(SaltSize);
+
+ // 2. 从原始密钥和盐值派生AES密钥
+ byte[] derivedKey = DeriveKey(key,salt);
+
+ // 3. AES加密逻辑
+ byte[] encryptedData;
+ using(Aes aes = Aes.Create()) {
+ aes.Key = derivedKey;
+ aes.GenerateIV(); // 生成随机IV(初始化向量)
+ aes.Mode = CipherMode.CBC;
+ aes.Padding = PaddingMode.PKCS7;
+
+ // 创建加密器
+ ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key,aes.IV);
+
+ using(MemoryStream msEncrypt = new MemoryStream()) {
+ // 先写入IV(解密时需要)
+ msEncrypt.Write(aes.IV,0,aes.IV.Length);
+
+ // 写入加密数据
+ using(CryptoStream csEncrypt = new CryptoStream(msEncrypt,encryptor,CryptoStreamMode.Write))
+ using(StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
+ swEncrypt.Write(plainText);
+ }
+
+ encryptedData = msEncrypt.ToArray();
+ }
+ }
+
+ // 4. 拼接加密数据和盐值(格式:[加密数据][盐值])
+ byte[] result = new byte[encryptedData.Length + SaltSize];
+ Array.Copy(encryptedData,0,result,0,encryptedData.Length);
+ Array.Copy(salt,0,result,encryptedData.Length,SaltSize);
+
+ // 转换为Base64返回
+ return Convert.ToBase64String(result);
+ }
+
+ public string Decrypt(string cipherText,string key) {
+ // 验证输入
+ if(string.IsNullOrEmpty(cipherText))
+ throw new ArgumentException("加密字符串不能为空",nameof(cipherText));
+ if(string.IsNullOrEmpty(key))
+ throw new ArgumentException("密钥不能为空",nameof(key));
+
+ // 1. 转换Base64为字节数组
+ byte[] fullData;
+ try {
+ fullData = Convert.FromBase64String(cipherText);
+ }
+ catch(FormatException) {
+ throw new ArgumentException("加密字符串不是有效的Base64格式",nameof(cipherText));
+ }
+
+ // 2. 验证数据长度(至少包含IV+盐值)
+ if(fullData.Length < 16 + SaltSize) // IV固定16字节 + 盐值长度
+ throw new ArgumentException("加密字符串无效(长度不足)",nameof(cipherText));
+
+ // 3. 提取盐值(从尾部提取)
+ byte[] salt = new byte[SaltSize];
+ Array.Copy(fullData,fullData.Length - SaltSize,salt,0,SaltSize);
+
+ // 4. 提取加密数据(排除尾部盐值)
+ byte[] encryptedData = new byte[fullData.Length - SaltSize];
+ Array.Copy(fullData,0,encryptedData,0,encryptedData.Length);
+
+ // 5. 从原始密钥和盐值派生AES密钥(与加密时一致)
+ byte[] derivedKey = DeriveKey(key,salt);
+
+ // 6. AES解密逻辑
+ using(Aes aes = Aes.Create()) {
+ aes.Key = derivedKey;
+ aes.Mode = CipherMode.CBC;
+ aes.Padding = PaddingMode.PKCS7;
+
+ // 提取IV(加密数据的前16字节)
+ byte[] iv = new byte[16];
+ Array.Copy(encryptedData,0,iv,0,iv.Length);
+ aes.IV = iv;
+
+ // 创建解密器
+ ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key,aes.IV);
+
+ // 解密数据(排除IV部分)
+ using(MemoryStream msDecrypt = new MemoryStream(encryptedData,16,encryptedData.Length - 16))
+ using(CryptoStream csDecrypt = new CryptoStream(msDecrypt,decryptor,CryptoStreamMode.Read))
+ using(StreamReader srDecrypt = new StreamReader(csDecrypt)) {
+ return srDecrypt.ReadToEnd();
+ }
+ }
+ }
+
+ ///
+ /// 基于PBKDF2算法派生密钥
+ ///
+ private byte[] DeriveKey(string rawKey,byte[] salt) {
+ using(Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(
+ rawKey,
+ salt,
+ Iterations,
+ HashAlgorithm)) {
+ return deriveBytes.GetBytes(KeySize);
+ }
+ }
+}
\ No newline at end of file
diff --git a/PrivateBox/MainForm.Designer.cs b/PrivateBox/MainForm.Designer.cs
new file mode 100644
index 0000000..a88ee60
--- /dev/null
+++ b/PrivateBox/MainForm.Designer.cs
@@ -0,0 +1,195 @@
+namespace PrivateBox
+{
+ partial class MainForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing) {
+ if(disposing && (components != null)) {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent() {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
+ toolStripContainer1 = new ToolStripContainer();
+ splitContainer1 = new SplitContainer();
+ lbKeyList = new ListBox();
+ splitContainer2 = new SplitContainer();
+ toolStrip1 = new ToolStrip();
+ btEdit = new ToolStripButton();
+ btSave = new ToolStripButton();
+ btCancel = new ToolStripButton();
+ tbMessage = new RichTextBox();
+ toolStripContainer1.ContentPanel.SuspendLayout();
+ toolStripContainer1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
+ splitContainer1.Panel1.SuspendLayout();
+ splitContainer1.Panel2.SuspendLayout();
+ splitContainer1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)splitContainer2).BeginInit();
+ splitContainer2.Panel1.SuspendLayout();
+ splitContainer2.Panel2.SuspendLayout();
+ splitContainer2.SuspendLayout();
+ toolStrip1.SuspendLayout();
+ SuspendLayout();
+ //
+ // toolStripContainer1
+ //
+ //
+ // toolStripContainer1.ContentPanel
+ //
+ toolStripContainer1.ContentPanel.Controls.Add(splitContainer1);
+ toolStripContainer1.ContentPanel.Size = new Size(756,379);
+ toolStripContainer1.Dock = DockStyle.Fill;
+ toolStripContainer1.Location = new Point(0,0);
+ toolStripContainer1.Name = "toolStripContainer1";
+ toolStripContainer1.Size = new Size(756,404);
+ toolStripContainer1.TabIndex = 0;
+ toolStripContainer1.Text = "toolStripContainer1";
+ //
+ // splitContainer1
+ //
+ splitContainer1.Dock = DockStyle.Fill;
+ splitContainer1.Location = new Point(0,0);
+ splitContainer1.Name = "splitContainer1";
+ //
+ // splitContainer1.Panel1
+ //
+ splitContainer1.Panel1.Controls.Add(lbKeyList);
+ //
+ // splitContainer1.Panel2
+ //
+ splitContainer1.Panel2.Controls.Add(splitContainer2);
+ splitContainer1.Size = new Size(756,379);
+ splitContainer1.SplitterDistance = 285;
+ splitContainer1.TabIndex = 0;
+ //
+ // lbKeyList
+ //
+ lbKeyList.Dock = DockStyle.Fill;
+ lbKeyList.FormattingEnabled = true;
+ lbKeyList.ItemHeight = 17;
+ lbKeyList.Location = new Point(0,0);
+ lbKeyList.Name = "lbKeyList";
+ lbKeyList.Size = new Size(285,379);
+ lbKeyList.TabIndex = 0;
+ //
+ // splitContainer2
+ //
+ splitContainer2.Dock = DockStyle.Fill;
+ splitContainer2.Location = new Point(0,0);
+ splitContainer2.Name = "splitContainer2";
+ splitContainer2.Orientation = Orientation.Horizontal;
+ //
+ // splitContainer2.Panel1
+ //
+ splitContainer2.Panel1.Controls.Add(toolStrip1);
+ //
+ // splitContainer2.Panel2
+ //
+ splitContainer2.Panel2.Controls.Add(tbMessage);
+ splitContainer2.Size = new Size(467,379);
+ splitContainer2.SplitterDistance = 25;
+ splitContainer2.TabIndex = 1;
+ //
+ // toolStrip1
+ //
+ toolStrip1.Items.AddRange(new ToolStripItem[] { btEdit,btSave,btCancel });
+ toolStrip1.Location = new Point(0,0);
+ toolStrip1.Name = "toolStrip1";
+ toolStrip1.Size = new Size(467,27);
+ toolStrip1.TabIndex = 0;
+ toolStrip1.Text = "toolStrip1";
+ //
+ // btEdit
+ //
+ btEdit.DisplayStyle = ToolStripItemDisplayStyle.Text;
+ btEdit.Image = (Image)resources.GetObject("btEdit.Image");
+ btEdit.ImageTransparentColor = Color.Magenta;
+ btEdit.Margin = new Padding(3);
+ btEdit.Name = "btEdit";
+ btEdit.Size = new Size(36,21);
+ btEdit.Text = "编辑";
+ //
+ // btSave
+ //
+ btSave.DisplayStyle = ToolStripItemDisplayStyle.Text;
+ btSave.Image = (Image)resources.GetObject("btSave.Image");
+ btSave.ImageTransparentColor = Color.Magenta;
+ btSave.Margin = new Padding(3);
+ btSave.Name = "btSave";
+ btSave.Size = new Size(36,21);
+ btSave.Text = "保存";
+ //
+ // btCancel
+ //
+ btCancel.DisplayStyle = ToolStripItemDisplayStyle.Text;
+ btCancel.Image = (Image)resources.GetObject("btCancel.Image");
+ btCancel.ImageTransparentColor = Color.Magenta;
+ btCancel.Margin = new Padding(3);
+ btCancel.Name = "btCancel";
+ btCancel.Size = new Size(36,21);
+ btCancel.Text = "取消";
+ //
+ // tbMessage
+ //
+ tbMessage.Dock = DockStyle.Fill;
+ tbMessage.Location = new Point(0,0);
+ tbMessage.Name = "tbMessage";
+ tbMessage.Size = new Size(467,350);
+ tbMessage.TabIndex = 0;
+ tbMessage.Text = "tbMessage";
+ //
+ // MainForm
+ //
+ AutoScaleDimensions = new SizeF(7F,17F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(756,404);
+ Controls.Add(toolStripContainer1);
+ Name = "MainForm";
+ Text = "主窗口";
+ toolStripContainer1.ContentPanel.ResumeLayout(false);
+ toolStripContainer1.ResumeLayout(false);
+ toolStripContainer1.PerformLayout();
+ splitContainer1.Panel1.ResumeLayout(false);
+ splitContainer1.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit();
+ splitContainer1.ResumeLayout(false);
+ splitContainer2.Panel1.ResumeLayout(false);
+ splitContainer2.Panel1.PerformLayout();
+ splitContainer2.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)splitContainer2).EndInit();
+ splitContainer2.ResumeLayout(false);
+ toolStrip1.ResumeLayout(false);
+ toolStrip1.PerformLayout();
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private ToolStripContainer toolStripContainer1;
+ private SplitContainer splitContainer1;
+ private ListBox lbKeyList;
+ private RichTextBox tbMessage;
+ private SplitContainer splitContainer2;
+ private ToolStrip toolStrip1;
+ private ToolStripButton btEdit;
+ private ToolStripButton btSave;
+ private ToolStripButton btCancel;
+ }
+}
\ No newline at end of file
diff --git a/PrivateBox/MainForm.cs b/PrivateBox/MainForm.cs
new file mode 100644
index 0000000..9dafedb
--- /dev/null
+++ b/PrivateBox/MainForm.cs
@@ -0,0 +1,22 @@
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace PrivateBox
+{
+ public partial class MainForm:Form
+ {
+ public IEncryptionService Encrytion { get; init; }
+ public MainForm(IServiceProvider provider) {
+ InitializeComponent();
+ this.Encrytion = provider.GetRequiredService();
+ }
+ }
+}
diff --git a/PrivateBox/MainForm.resx b/PrivateBox/MainForm.resx
new file mode 100644
index 0000000..a03afcd
--- /dev/null
+++ b/PrivateBox/MainForm.resx
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
+ J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
+ CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
+ AAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
+ J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
+ CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
+ AAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
+ J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
+ CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
+ AAAAAElFTkSuQmCC
+
+
+
\ No newline at end of file
diff --git a/PrivateBox/PrivateBox.csproj b/PrivateBox/PrivateBox.csproj
new file mode 100644
index 0000000..f89cb0b
--- /dev/null
+++ b/PrivateBox/PrivateBox.csproj
@@ -0,0 +1,31 @@
+
+
+
+ WinExe
+ net7.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
\ No newline at end of file
diff --git a/PrivateBox/Program.cs b/PrivateBox/Program.cs
new file mode 100644
index 0000000..e3ec641
--- /dev/null
+++ b/PrivateBox/Program.cs
@@ -0,0 +1,36 @@
+using Microsoft.Extensions.DependencyInjection;
+
+namespace PrivateBox
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main() {
+ ApplicationConfiguration.Initialize();
+
+ IServiceCollection services = new ServiceCollection();
+ var appConfig = new AppConfig();
+ services.AddSingleton(appConfig);
+ AddServices(services,appConfig);
+ using ServiceProvider provider = GetServiceProvider(services);
+ var mainForm = provider.GetRequiredService();
+ Application.Run(mainForm);
+ }
+
+ static void AddServices(IServiceCollection services,AppConfig config) {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ static ServiceProvider GetServiceProvider(IServiceCollection services) {
+ ServiceProvider? provider = null;
+ services.AddSingleton(sp => provider!);
+ provider = services.BuildServiceProvider();
+ return provider;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PrivateBox/Properties/Resources.Designer.cs b/PrivateBox/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..6ecc401
--- /dev/null
+++ b/PrivateBox/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace PrivateBox.Properties {
+ using System;
+
+
+ ///
+ /// 一个强类型的资源类,用于查找本地化的字符串等。
+ ///
+ // 此类是由 StronglyTypedResourceBuilder
+ // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+ // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+ // (以 /str 作为命令选项),或重新生成 VS 项目。
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 返回此类使用的缓存的 ResourceManager 实例。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PrivateBox.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 重写当前线程的 CurrentUICulture 属性,对
+ /// 使用此强类型资源类的所有资源查找执行重写。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/PrivateBox/Properties/Resources.resx b/PrivateBox/Properties/Resources.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/PrivateBox/Properties/Resources.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file