Skip to content

Commit a879957

Browse files
committedFeb 11, 2025
updated to v2.13.3
1 parent a188744 commit a879957

File tree

4 files changed

+129
-83
lines changed

4 files changed

+129
-83
lines changed
 

‎Assets/OxGFrame/AssetLoader/Scripts/Runtime/Bundle/BundleInfos.cs

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
using MyBox;
2-
using System;
1+
using System;
32
using System.Collections.Generic;
43
using UnityEngine;
54
using YooAsset;
6-
using static OxGFrame.AssetLoader.Bundle.BundleConfig;
75

86
namespace OxGFrame.AssetLoader.Bundle
97
{
@@ -12,11 +10,11 @@ public class DecryptInfo : IDisposable
1210
{
1311
[SerializeField, Tooltip("Bundle decryption (case-insensitive).\n\n[NONE], \n[OFFSET, dummySize], \n[XOR, key], \n[HT2XOR, headKey, tailKey, jumpKey], \n[HT2XORPLUS, headKey, tailKey, jump1Key, jump2Key], \n[AES, key, iv]\n\nex: \n\"none\" \n\"offset, 12\" \n\"xor, 23\" \n\"ht2xor, 34, 45, 56\" \n\"ht2xorplus, 34, 45, 56, 78\" \n\"aes, key, iv\"")]
1412
private string _decryptArgs = BundleConfig.CryptogramType.NONE;
15-
[SerializeField, Tooltip("Can encrypt string data in memory.")]
13+
[SerializeField, Tooltip("If checked, complex encryption will be performed in memory (more GC).\n\nIf unchecked, simple encryption will be performed in memory (less GC).")]
1614
public bool secureString = true;
17-
[SerializeField, Tooltip("The longer the length, the safer it is. 16 bytes (128 bits), 32 bytes (256 bits)"), ConditionalField(nameof(secureString))]
15+
[SerializeField, Tooltip("The longer the length, the safer it is. 16 bytes (128 bits), 32 bytes (256 bits)")]
1816
private int _saltSize = 1 << 4;
19-
[SerializeField, Tooltip("The longer the length, the safer it is. 16 bytes (128 bits), 32 bytes (256 bits)"), ConditionalField(nameof(secureString))]
17+
[SerializeField, Tooltip("The longer the length, the safer it is. 16 bytes (128 bits), 32 bytes (256 bits)")]
2018
private int _dummySize = 1 << 5;
2119

2220
public string GetDecryptArgs()
@@ -58,7 +56,7 @@ public class GroupInfo
5856
public abstract class PackageInfoWithBuild
5957
{
6058
[Tooltip("Only for EditorSimulateMode")]
61-
public BuildMode buildMode;
59+
public BundleConfig.BuildMode buildMode;
6260
public string packageName;
6361

6462
/// <summary>
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,88 @@
11
using System;
2+
using System.Buffers;
23
using System.IO;
34
using System.Security.Cryptography;
5+
using System.Text;
46

57
namespace OxGFrame.AssetLoader.Utility.SecureMemory
68
{
79
internal class SecureString : IDisposable
810
{
9-
// Secured
10-
private bool _secured = true;
11-
12-
// Opaque Data
13-
private byte[] _opaqueData = null;
14-
15-
// Salt
16-
private byte[] _salt = null;
17-
18-
// Dummy
19-
private int _l1;
20-
private int _l2;
11+
/// <summary>
12+
/// 是否啟用加密
13+
/// </summary>
14+
private readonly bool _secured;
15+
16+
/// <summary>
17+
/// 加密後的數據
18+
/// </summary>
19+
private byte[] _opaqueData;
20+
21+
/// <summary>
22+
/// 加密用的 salt
23+
/// </summary>
24+
private byte[] _salt;
25+
26+
/// <summary>
27+
/// 用於混淆的長度參數 l1
28+
/// </summary>
29+
private readonly int _l1;
30+
31+
/// <summary>
32+
/// 用於混淆的長度參數 l2
33+
/// </summary>
34+
private readonly int _l2;
35+
36+
/// <summary>
37+
/// 資源釋放標記
38+
/// </summary>
39+
private bool _disposed = false;
40+
41+
/// <summary>
42+
/// 重用 Random 實例, 降低 GC
43+
/// </summary>
44+
private static readonly Random _random = new Random();
45+
46+
/// <summary>
47+
/// 重用 UTF8 編碼實例, 降低 GC
48+
/// </summary>
49+
private static readonly UTF8Encoding _utf8Encoding = new UTF8Encoding(false);
2150

2251
public SecureString(string input, bool secured = true, int saltSize = 1 << 4, int dummySize = 1 << 5)
2352
{
24-
// Enabled encrypt
2553
this._secured = secured;
2654

27-
// Dummy
2855
if (dummySize < 1 << 1) dummySize = 1 << 1;
2956

30-
// Random dummy size
31-
Random rnd = new Random();
32-
this._l1 = rnd.Next(dummySize >> 1, dummySize + 1);
33-
this._l2 = rnd.Next(dummySize >> 1, dummySize + 1);
34-
3557
if (this._secured)
3658
{
37-
// Salt
3859
if (saltSize < 1 << 1) saltSize = 1 << 1;
3960
this._GenerateSalt(saltSize);
40-
41-
// Encrypt data with aes
4261
this._opaqueData = this._Encrypt(input);
4362
}
44-
// String to bytes with dummy
45-
else this._opaqueData = StringWithDummy.StringToBytesWithDummy(input, this._l1, this._l2);
63+
else
64+
{
65+
// 使用 lock 來確保 Random 的執行緒安全
66+
lock (_random)
67+
{
68+
this._l1 = _random.Next(dummySize >> 1, dummySize + 1);
69+
this._l2 = _random.Next(dummySize >> 1, dummySize + 1);
70+
this._opaqueData = StringWithDummy.StringToBytesWithDummy(input, this._l1, this._l2);
71+
}
72+
}
73+
}
74+
75+
~SecureString()
76+
{
77+
this.Dispose();
4678
}
4779

4880
private void _GenerateSalt(int saltSize)
4981
{
50-
using (var random = new RNGCryptoServiceProvider())
82+
this._salt = ArrayPool<byte>.Shared.Rent(saltSize);
83+
using (var random = RandomNumberGenerator.Create())
5184
{
52-
this._salt = new byte[saltSize];
53-
random.GetBytes(this._salt);
85+
random.GetBytes(this._salt, 0, saltSize);
5486
}
5587
}
5688

@@ -65,88 +97,100 @@ private byte[] _Encrypt(string input)
6597
{
6698
aesAlg.Key = this._salt;
6799

100+
// 從池中租用 IV buffer
101+
IV = ArrayPool<byte>.Shared.Rent(aesAlg.BlockSize >> 3);
68102
aesAlg.GenerateIV();
69-
IV = aesAlg.IV;
103+
Array.Copy(aesAlg.IV, IV, aesAlg.IV.Length);
70104

71105
aesAlg.Mode = CipherMode.CBC;
72106

73-
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
107+
// 預估加密後的大小 (粗略估計, 可根據實際情況調整)
108+
int estimatedSize = (input.Length * 2) + 32;
109+
var msEncrypt = new MemoryStream(estimatedSize);
74110

75-
// Create the streams used for encryption.
76-
using (var msEncrypt = new MemoryStream())
111+
using (var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, IV))
112+
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
77113
{
78-
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
79-
{
80-
using (var swEncrypt = new StreamWriter(csEncrypt))
81-
{
82-
// Write all data to the stream.
83-
swEncrypt.Write(input);
84-
}
85-
encrypted = msEncrypt.ToArray();
86-
}
114+
// 直接使用 UTF8 編碼寫入, 避免 StreamWriter 的額外開銷
115+
byte[] inputBytes = _utf8Encoding.GetBytes(input);
116+
csEncrypt.Write(inputBytes, 0, inputBytes.Length);
87117
}
118+
119+
encrypted = msEncrypt.ToArray();
120+
msEncrypt.Dispose();
88121
}
89122

90-
var combinedIvCt = new byte[IV.Length + encrypted.Length];
91-
Array.Copy(IV, 0, combinedIvCt, 0, IV.Length);
92-
Array.Copy(encrypted, 0, combinedIvCt, IV.Length, encrypted.Length);
123+
// 組合 IV 和加密數據
124+
var result = new byte[IV.Length + encrypted.Length];
125+
Array.Copy(IV, 0, result, 0, IV.Length);
126+
Array.Copy(encrypted, 0, result, IV.Length, encrypted.Length);
93127

94-
// Return the encrypted bytes from the memory stream.
95-
return combinedIvCt;
128+
// 歸還 IV buffer
129+
ArrayPool<byte>.Shared.Return(IV);
96130

131+
return result;
97132
}
98133

99134
public string Decrypt()
100135
{
101-
if (!this._secured) return StringWithDummy.BytesWithDummyToString(this._opaqueData, this._l1, this._l2);
136+
if (!this._secured)
137+
return StringWithDummy.BytesWithDummyToString(this._opaqueData, this._l1, this._l2);
102138

103-
// Declare the string used to hold
104-
// the decrypted text.
105-
string plaintext = null;
106-
107-
// Create an Aes object
108-
// with the specified key and IV.
109139
using (Aes aesAlg = Aes.Create())
110140
{
111141
aesAlg.Key = this._salt;
112142

113-
byte[] IV = new byte[aesAlg.BlockSize >> 3];
114-
byte[] cipherText = new byte[this._opaqueData.Length - IV.Length];
115-
116-
Array.Copy(this._opaqueData, IV, IV.Length);
117-
Array.Copy(this._opaqueData, IV.Length, cipherText, 0, cipherText.Length);
118-
119-
aesAlg.IV = IV;
143+
// 從池中租用 IV buffer
144+
int ivLength = aesAlg.BlockSize >> 3;
145+
byte[] IV = ArrayPool<byte>.Shared.Rent(ivLength);
146+
byte[] cipherText = new byte[this._opaqueData.Length - ivLength];
120147

121-
aesAlg.Mode = CipherMode.CBC;
148+
try
149+
{
150+
Array.Copy(this._opaqueData, IV, ivLength);
151+
Array.Copy(this._opaqueData, ivLength, cipherText, 0, cipherText.Length);
122152

123-
// Create a decrytor to perform the stream transform.
124-
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
153+
aesAlg.IV = IV;
154+
aesAlg.Mode = CipherMode.CBC;
125155

126-
// Create the streams used for decryption.
127-
using (var msDecrypt = new MemoryStream(cipherText))
128-
{
156+
using (var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
157+
using (var msDecrypt = new MemoryStream(cipherText))
129158
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
130159
{
131-
using (var srDecrypt = new StreamReader(csDecrypt))
160+
// 直接將解密後的數據讀入 byte array, 然後轉換為字符串
161+
using (var ms = new MemoryStream())
132162
{
133-
// Read the decrypted bytes from the decrypting stream
134-
// and place them in a string.
135-
plaintext = srDecrypt.ReadToEnd();
163+
csDecrypt.CopyTo(ms);
164+
return _utf8Encoding.GetString(ms.ToArray());
136165
}
137166
}
138167
}
168+
finally
169+
{
170+
// 確保歸還 IV buffer
171+
ArrayPool<byte>.Shared.Return(IV);
172+
}
139173
}
140-
141-
return plaintext;
142174
}
143175

144176
public void Dispose()
145177
{
146-
if (this._opaqueData != null) Array.Clear(this._opaqueData, 0, this._opaqueData.Length);
147-
this._opaqueData = null;
148-
if (this._salt != null) Array.Clear(this._salt, 0, this._salt.Length);
149-
this._salt = null;
178+
if (!this._disposed)
179+
{
180+
if (this._opaqueData != null)
181+
{
182+
Array.Clear(this._opaqueData, 0, this._opaqueData.Length);
183+
this._opaqueData = null;
184+
}
185+
186+
if (this._salt != null)
187+
{
188+
ArrayPool<byte>.Shared.Return(this._salt);
189+
this._salt = null;
190+
}
191+
192+
this._disposed = true;
193+
}
150194
}
151195
}
152196
}

‎Assets/OxGFrame/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG
22

3+
## [2.13.3] - 2025-02-11
4+
- Modified PatchLauncher SecureString Tooltip: If checked, complex encryption will be performed in memory (more GC). If unchecked, simple encryption will be performed in memory (less GC).
5+
- Optimized SecureString to reduce GC by more than half.
6+
37
## [2.13.2] - 2025-02-05
48
- Added CPBase MonoDrive feature. When enabled, it supports initialization driven by MonoBehaviour, allowing it to be directly placed in the scene without needing to be loaded through CPManager.
59
- Fixed the issue in FrameManager where an InvalidOperationException could occur due to collection modification during enumeration.

‎Assets/OxGFrame/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "com.michaelo.oxgframe",
33
"displayName": "OxGFrame",
44
"description": "The OxGFrame is a framework based on Unity for accelerating game development. Supports multi-platform Win, OSX, Android, iOS, WebGL.",
5-
"version": "2.13.2",
5+
"version": "2.13.3",
66
"unity": "2021.3",
77
"license": "MIT",
88
"samples": [

0 commit comments

Comments
 (0)
Please sign in to comment.