Skip to content

Commit 1b397f2

Browse files
authored
Merge pull request #12 from f-shake/dev
对加密解密进行了改造;完善了帮助文件;新增了启动界面
2 parents e6638cd + 711bf3e commit 1b397f2

File tree

27 files changed

+1225
-803
lines changed

27 files changed

+1225
-803
lines changed

ArchiveMaster.Core/Helpers/AesExtension.cs

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,23 @@ public static class AesExtension
1919
/// <param name="array">要解密的 byte[] 数组</param>
2020
/// <param name="key"></param>
2121
/// <returns></returns>
22-
public static byte[] Decrypt(this Aes manager, byte[] array)
22+
public static byte[] Decrypt(this Aes aes, byte[] encryptedDataWithIv)
2323
{
24-
var decryptor = manager.CreateDecryptor();
25-
return decryptor.TransformFinalBlock(array, 0, array.Length);
24+
int ivSize = aes.BlockSize / 8; // AES IV 固定为 16 字节
25+
if (encryptedDataWithIv.Length < ivSize)
26+
{
27+
throw new ArgumentException("无效的加密数据:缺少 IV");
28+
}
29+
30+
byte[] iv = new byte[ivSize];
31+
byte[] ciphertext = new byte[encryptedDataWithIv.Length - ivSize];
32+
33+
Buffer.BlockCopy(encryptedDataWithIv, 0, iv, 0, ivSize);
34+
Buffer.BlockCopy(encryptedDataWithIv, ivSize, ciphertext, 0, ciphertext.Length);
35+
36+
aes.IV = iv;
37+
using ICryptoTransform decryptor = aes.CreateDecryptor();
38+
return decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
2639
}
2740

2841
public static void DecryptFile(this Aes manager, string sourcePath, string targetPath,
@@ -108,12 +121,28 @@ public static void DecryptFile(this Aes manager, string sourcePath, string targe
108121
/// <param name="array">要加密的 byte[] 数组</param>
109122
/// <param name="key"></param>
110123
/// <returns></returns>
111-
public static byte[] Encrypt(this Aes manager, byte[] array)
124+
public static byte[] Encrypt(this Aes aes, byte[] plaintext,byte[] iv=null)
112125
{
113-
var encryptor = manager.CreateEncryptor();
114-
return encryptor.TransformFinalBlock(array, 0, array.Length);
115-
}
126+
if (iv == null)
127+
{
128+
aes.GenerateIV();
129+
iv = aes.IV;
130+
}
131+
else if (iv.Length != 16)
132+
{
133+
throw new Exception("iv应当为空表示自动生成,或提供一个长度为16的字符数组");
134+
}
116135

136+
using (ICryptoTransform encryptor = aes.CreateEncryptor())
137+
{
138+
byte[] ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);
139+
140+
byte[] result = new byte[iv.Length + ciphertext.Length];
141+
Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
142+
Buffer.BlockCopy(ciphertext, 0, result, iv.Length, ciphertext.Length);
143+
return result;
144+
}
145+
}
117146
public static void EncryptFile(this Aes manager, string sourcePath, string targetPath,
118147
int bufferLength = 0,
119148
IProgress<FileCopyProgress> progress = null,
@@ -123,7 +152,7 @@ public static void EncryptFile(this Aes manager, string sourcePath, string targe
123152
{
124153
throw new IOException($"目标文件{targetPath}已存在");
125154
}
126-
155+
manager.GenerateIV();
127156
if (bufferLength <= 0)
128157
{
129158
var fileInfo = new FileInfo(sourcePath);
@@ -180,32 +209,13 @@ public static void EncryptFile(this Aes manager, string sourcePath, string targe
180209
}
181210
}
182211

183-
public static Aes SetStringIV(this Aes manager, string iv, char fill = (char)0, Encoding encoding = null)
212+
public static Aes SetStringKey(this Aes manager, string key)
184213
{
185-
manager.IV = GetBytesFromString(manager, iv, fill, encoding);
214+
using var deriveBytes = new Rfc2898DeriveBytes(key, Encoding.UTF8.GetBytes(nameof(ArchiveMaster)), 100000,HashAlgorithmName.SHA256);
215+
manager.Key = deriveBytes.GetBytes(manager.KeySize / 8);
186216
return manager;
187217
}
188218

189-
public static Aes SetStringKey(this Aes manager, string key, char fill = (char)0, Encoding encoding = null)
190-
{
191-
manager.Key = GetBytesFromString(manager, key, fill, encoding);
192-
return manager;
193-
}
194-
private static byte[] GetBytesFromString(Aes manager, string input, char fill, Encoding encoding)
195-
{
196-
input ??= "";
197-
int length = manager.BlockSize / 8;
198-
if (input.Length < length)
199-
{
200-
input += new string(fill, length - input.Length);
201-
}
202-
else if (input.Length > length)
203-
{
204-
input = input[..length];
205-
}
206-
207-
return (encoding ?? Encoding.UTF8).GetBytes(input);
208-
}
209219
private static void HandleException(string target, Exception ex)
210220
{
211221
try

ArchiveMaster.Module.FileBackupper/ViewModels/BackupManageCenterViewModel.Snapshots.cs

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ public partial class BackupManageCenterViewModel
1717
private BackupSnapshotEntity selectedSnapshot;
1818

1919
[ObservableProperty]
20-
private ObservableCollection<BackupSnapshotEntity> snapshots;
20+
private FullSnapshotItem selectedFullSnapshot;
21+
22+
[ObservableProperty]
23+
private ObservableCollection<FullSnapshotItem> fullSnapshots;
2124

2225
[ObservableProperty]
2326
private int totalSnapshotCount;
@@ -56,7 +59,35 @@ private async Task LoadSnapshotsAsync()
5659
try
5760
{
5861
DbService db = new DbService(SelectedTask);
59-
Snapshots = new ObservableCollection<BackupSnapshotEntity>(await db.GetSnapshotsAsync());
62+
var snapshots = await db.GetSnapshotsAsync();
63+
FullSnapshotItem fullSnapshot = null;
64+
FullSnapshots = new ObservableCollection<FullSnapshotItem>();
65+
foreach (var snapshot in snapshots)
66+
{
67+
switch (snapshot.Type)
68+
{
69+
case SnapshotType.Full:
70+
case SnapshotType.VirtualFull:
71+
fullSnapshot = new FullSnapshotItem(snapshot);
72+
FullSnapshots.Add(fullSnapshot);
73+
break;
74+
case SnapshotType.Increment:
75+
if (fullSnapshot == null)
76+
{
77+
throw new Exception($"增量快照{snapshot.BeginTime}前没有全量快照");
78+
}
79+
80+
fullSnapshot.Snapshots.Add(snapshot);
81+
break;
82+
default:
83+
throw new ArgumentOutOfRangeException();
84+
}
85+
}
86+
87+
if (FullSnapshots.Count > 0)
88+
{
89+
SelectedFullSnapshot = FullSnapshots[^1];
90+
}
6091
}
6192
catch (Exception ex)
6293
{
@@ -68,22 +99,20 @@ private async Task LoadSnapshotsAsync()
6899
[RelayCommand]
69100
private async Task DeleteSnapshotAsync(BackupSnapshotEntity snapshot)
70101
{
102+
if (backupService.IsBackingUp)
103+
{
104+
await this.ShowErrorAsync("删除快照",$"目前有任务正在备份,无法删除快照");
105+
return;
106+
}
71107
string message = null;
72-
int index = Snapshots.IndexOf(snapshot);
73-
if (index == Snapshots.Count - 1) //最后一个,可以直接删
108+
int index = SelectedFullSnapshot.Snapshots.IndexOf(snapshot);
109+
if (SelectedFullSnapshot.Snapshots.Count <= 1 || index == SelectedFullSnapshot.Snapshots.Count - 1) //最后一个,可以直接删
74110
{
75111
message = "是否删除此快照?";
76112
}
77113
else
78114
{
79-
if (Snapshots[index + 1].Type is SnapshotType.Increment) //后面跟着增量备份,会把后面的也一起删了
80-
{
81-
message = "删除此快照,将同步删除后续的增量快照,是否删除此快照?";
82-
}
83-
else //后面跟着全量备份,无影响
84-
{
85-
message = "是否删除此快照?";
86-
}
115+
message = "删除此快照,将同步删除后续的增量快照,是否删除此快照?";
87116
}
88117

89118
bool confirm = true.Equals(await this.SendMessage(new CommonDialogMessage()

ArchiveMaster.Module.FileBackupper/ViewModels/BackupManageCenterViewModel.Tasks.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ private async Task CancelMakingBackup()
3535
[RelayCommand]
3636
private async Task LoadTasksAsync()
3737
{
38-
Snapshots = null;
38+
FullSnapshots = null;
3939
SelectedTask = null;
4040
Tasks = new ObservableCollection<BackupTask>(Config.Tasks);
4141
await Tasks.UpdateStatusAsync();
@@ -57,7 +57,7 @@ private async Task MakeBackupAsync(SnapshotType type)
5757

5858
async partial void OnSelectedTaskChanged(BackupTask oldValue, BackupTask newValue)
5959
{
60-
Snapshots = null;
60+
FullSnapshots = null;
6161
LastLog = null;
6262

6363
if (oldValue != null)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Collections.ObjectModel;
2+
using ArchiveMaster.Models;
3+
using CommunityToolkit.Mvvm.ComponentModel;
4+
5+
namespace ArchiveMaster.ViewModels;
6+
7+
public partial class FullSnapshotItem:ObservableObject
8+
{
9+
public FullSnapshotItem(BackupSnapshotEntity fullSnapshot)
10+
{
11+
FullSnapshot = fullSnapshot;
12+
Snapshots = [fullSnapshot];
13+
}
14+
15+
[ObservableProperty]
16+
private BackupSnapshotEntity fullSnapshot;
17+
18+
[ObservableProperty]
19+
private ObservableCollection<BackupSnapshotEntity> snapshots;
20+
}

ArchiveMaster.Module.FileBackupper/Views/BackupManageCenterPanel.axaml

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@
6363
Classes="Icon"
6464
Command="{Binding LoadTasksCommand}"
6565
Content="{StaticResource ReturnToCall}"
66-
ToolTip.Tip="返回" />
66+
ToolTip.Tip="返回">
67+
<Button.RenderTransform>
68+
<ScaleTransform ScaleX="-1" />
69+
</Button.RenderTransform>
70+
</Button>
6771
</StackPanel>
6872

6973
<TabControl IsVisible="{Binding !!SelectedTask}">
@@ -84,21 +88,21 @@
8488
<Setter Property="HorizontalAlignment" Value="Center" />
8589
</Style>
8690
</TabControl.Styles>
87-
<TabItem
88-
Header="变更内容"
89-
IsVisible="{Binding !!SelectedSnapshot}">
90-
<v:SnapshotChangesPanel />
91-
</TabItem>
92-
<TabItem
93-
Header="快照文件"
94-
IsVisible="{Binding !!SelectedSnapshot}">
95-
<v:SnapshotFilesPanel />
96-
</TabItem>
97-
<TabItem
98-
Header="文件历史记录"
99-
IsVisible="{Binding !!SelectedFile}">
100-
<v:SnapshotFileHistoryPanel />
101-
</TabItem>
91+
<TabItem
92+
Header="变更内容"
93+
IsVisible="{Binding !!SelectedSnapshot}">
94+
<v:SnapshotChangesPanel />
95+
</TabItem>
96+
<TabItem
97+
Header="快照文件"
98+
IsVisible="{Binding !!SelectedSnapshot}">
99+
<v:SnapshotFilesPanel />
100+
</TabItem>
101+
<TabItem
102+
Header="文件历史记录"
103+
IsVisible="{Binding !!SelectedFile}">
104+
<v:SnapshotFileHistoryPanel />
105+
</TabItem>
102106
<TabItem
103107
Header="日志"
104108
IsVisible="{Binding SelectedSnapshot}">

ArchiveMaster.Module.FileBackupper/Views/SnapshotPanel.axaml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,21 @@
77
d:DesignHeight="450"
88
d:DesignWidth="800"
99
mc:Ignorable="d">
10-
<Grid RowDefinitions="*,8,Auto">
10+
<Grid RowDefinitions="Auto,4,Auto,8,Auto,4,*,8,Auto">
11+
<TextBlock Text="全量快照" />
12+
<ComboBox
13+
Grid.Row="2"
14+
HorizontalAlignment="Stretch"
15+
DisplayMemberBinding="{Binding FullSnapshot.BeginTime}"
16+
ItemsSource="{Binding FullSnapshots}"
17+
SelectedItem="{Binding SelectedFullSnapshot}" />
18+
<TextBlock
19+
Grid.Row="4"
20+
Text="全量快照下的所有快照" />
1121
<DataGrid
22+
Grid.Row="6"
1223
IsReadOnly="True"
13-
ItemsSource="{Binding Snapshots}"
24+
ItemsSource="{Binding SelectedFullSnapshot.Snapshots}"
1425
SelectedItem="{Binding SelectedSnapshot}">
1526
<DataGrid.Columns>
1627
<DataGridTextColumn
@@ -48,7 +59,7 @@
4859
</DataGrid.Columns>
4960
</DataGrid>
5061
<StackPanel
51-
Grid.Row="2"
62+
Grid.Row="8"
5263
Orientation="Horizontal">
5364
<Button
5465
Classes="Icon"

ArchiveMaster.Module.FileTools/Configs/EncryptorConfig.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,23 @@ namespace ArchiveMaster.Configs
77
{
88
public partial class EncryptorConfig : ConfigBase
99
{
10-
public enum EncryptorTaskType
11-
{
12-
Encrypt,
13-
Decrypt,
14-
}
15-
1610
[ObservableProperty]
1711
private CipherMode cipherMode = CipherMode.CBC;
1812

1913
[ObservableProperty]
2014
private bool deleteSourceFiles;
2115

2216
[ObservableProperty]
23-
private string encryptedDir;
17+
private bool encryptDirectoryStructure;
2418

2519
[ObservableProperty]
26-
private bool encryptDirectoryStructure;
20+
private string encryptedDir;
2721

2822
[ObservableProperty]
29-
private bool encryptFileNames;
23+
private FilenameDuplicationPolicy filenameDuplicationPolicy;
3024

3125
[ObservableProperty]
32-
private bool encryptFolderNames;
26+
private int keySize = 256;
3327

3428
[ObservableProperty]
3529
private PaddingMode paddingMode = PaddingMode.PKCS7;
@@ -42,13 +36,15 @@ public enum EncryptorTaskType
4236

4337
[ObservableProperty]
4438
private bool rememberPassword;
45-
46-
[ObservableProperty]
47-
private FilenameDuplicationPolicy filenameDuplicationPolicy;
4839

4940
[ObservableProperty]
5041
private EncryptorTaskType type = EncryptorTaskType.Encrypt;
5142

43+
public enum EncryptorTaskType
44+
{
45+
Encrypt,
46+
Decrypt,
47+
}
5248
public override void Check()
5349
{
5450
switch (Type)
@@ -63,6 +59,10 @@ public override void Check()
6359
throw new ArgumentOutOfRangeException();
6460
}
6561
CheckEmpty(Password,"密码");
62+
if (KeySize is not (128 or 192 or 256))
63+
{
64+
throw new Exception("密钥长度应当为128、192或256");
65+
}
6666
}
6767
}
6868
}

0 commit comments

Comments
 (0)