Skip to content

Commit 7ab6f60

Browse files
committed
publish 031
1 parent fb7fc4f commit 7ab6f60

File tree

11 files changed

+350
-2
lines changed

11 files changed

+350
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
### 2023
1818

19-
**一月份**[030](docs/episode-030.md) :high_brightness:
19+
**一月份**[031](docs/episode-031.md) :high_brightness: | [第 030 期](docs/episode-030.md)
2020

2121
### 2022
2222

docs/episode-030.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static (string, int, double) QueryCityData(string name)
3737
}
3838
```
3939

40-
1. 显式指定字段类型
40+
1. 显式指定字段类型
4141

4242
```csharp
4343
(string city1, int population1, double area1) = QueryCityData("New York City");

docs/episode-031.md

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
# .NET 每周分享第 30 期
2+
3+
## 卷首语
4+
5+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/suvery.png)
6+
7+
Jetbrains 公司发起的 `.NET` 生态开发者的调查问卷结果,主要包含下面的问题:
8+
9+
- C# 使用的版本
10+
- .NET 项目使用的语言
11+
- 开发项目的类型
12+
- CLR 使用的版本
13+
- IDE 或者编辑器使用
14+
- VS 插件使用
15+
- VS Code 插件使用
16+
- 单元测试框架
17+
- 性能调试频率
18+
19+
## 行业资讯
20+
21+
1、[VS 上搜索体验提升](https://devblogs.microsoft.com/visualstudio/new-better-search-in-visual-studio/)
22+
23+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/vssearch.png)
24+
25+
Visual Studio 提升了搜索的体验,主要分为了代码搜索和功能搜索。选择 `Ctrl + T` 快捷键进行搜索,而且可以使用 `f:` , `t:``m:` 前缀分别表示文件,类型和成员搜索。
26+
27+
## 文章推荐
28+
29+
1、[C# 代码加密算法汇总](https://code-maze.com/dotnet-cryptography-implementations/)
30+
31+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/encryption.png)
32+
33+
数据加密是现在计算机网络的基础,通过加密可以确保我们数据的安全性,那么在 `C#` 中如何使用这些加密算法呢?
34+
35+
1. Hash 加密
36+
37+
Hash 加密是一种单向加密,也就是说将一个输入转换到一个特定空间的数据。通常不能进行反向操作,通过这种方法可以判断输入的内容事否一致。通常有三种类别
38+
39+
- MD5
40+
41+
该算法已经被标记为不安全算法。
42+
43+
```csharp
44+
var strStreamOne = new MemoryStream(Encoding.UTF8.GetBytes("This is my password! Dont read me!"));
45+
byte[] hashOne;
46+
using (var hasher = MD5.Create())
47+
{
48+
hashOne = await hasher.ComputeHashAsync(strStreamOne);
49+
}
50+
var hashAsString = Convert.ToHexString(hashOne);
51+
Console.WriteLine("Hash Value:\n" + hashAsString)
52+
```
53+
54+
- SHA 族
55+
56+
通常有 `Sha-1`, `sha2` 这样的算法
57+
58+
```csharp
59+
var strStreamOne = new MemoryStream(Encoding.UTF8.GetBytes("This is my password! Dont read me!"));
60+
byte[] hashOne;
61+
using (var sha256 = SHA256.Create())
62+
{
63+
hashOne = await sha256.ComputeHashAsync(strStreamOne);
64+
}
65+
var hashAsString = Convert.ToHexString(hashOne);
66+
```
67+
68+
- HMAC
69+
70+
这是一个需要密钥才能生成的哈希算法
71+
72+
```csharp
73+
var strStreamOne = new MemoryStream(Encoding.UTF8.GetBytes("This is my password! Dont read me!"));
74+
byte[] hashOne;
75+
byte[] key = Encoding.UTF8.GetBytes("superSecretH4shKey1!");
76+
using (var hmac = new HMACSHA256(key))
77+
{
78+
hashOne = await hmac.ComputeHashAsync(strStreamOne);
79+
}
80+
var hashAsString = Convert.ToHexString(hashOne);
81+
```
82+
83+
2. 对称加密
84+
85+
这是一个可以进行加密和解密的算法,两端使用相同的密钥进行工作,通常使用 `AES` 算法
86+
87+
```csharp
88+
var dataStr = "This is corporate research! Dont read me!";
89+
var data = Encoding.UTF8.GetBytes(dataStr);
90+
var key = GenerateAESKey();
91+
var encryptedData = Encrypt(data, key, out var iv);
92+
var encryptedDataAsString = Convert.ToHexString(encryptedData);
93+
94+
public static byte[] Encrypt(byte[] data, byte[] key, out byte[] iv)
95+
{
96+
using (var aes = Aes.Create())
97+
{
98+
aes.Mode = CipherMode.CBC; // better security
99+
aes.Key = key;
100+
aes.GenerateIV(); // IV = Initialization Vector
101+
102+
using (var encryptor = aes.CreateEncryptor())
103+
{
104+
iv = aes.IV;
105+
return encryptor.TransformFinalBlock(data, 0, data.Length);
106+
}
107+
}
108+
}
109+
110+
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
111+
{
112+
using (var aes = Aes.Create())
113+
{
114+
aes.Key = key;
115+
aes.IV = iv;
116+
aes.Mode = CipherMode.CBC; // same as for encryption
117+
118+
using (var decryptor = aes.CreateDecryptor())
119+
{
120+
return decryptor.TransformFinalBlock(data, 0, data.Length);
121+
}
122+
}
123+
}
124+
public static byte[] GenerateAESKey()
125+
{
126+
var rnd = new RNGCryptoServiceProvider();
127+
var b = new byte[16];
128+
rnd.GetNonZeroBytes(b);
129+
return b;
130+
}
131+
```
132+
133+
3. 非对称加密
134+
135+
就是加密方和解密方使用不同的密钥来操作,通常分为公钥和私钥,公钥可以公开,任何人都可以加密。但是只有私钥才能解开,反之亦然,私钥加密的内容,只有公钥才能解开。这样可以保证私钥的安全性。最著名的就是 `RSA` 算法,这也是 `HTTPS` 协议的基石。
136+
137+
```csharp
138+
var dataStr = "This is corporate research! Dont read me!";
139+
var data = Encoding.UTF8.GetBytes(dataStr);
140+
var keyLength = 2048; // size in bits
141+
GenerateKeys(keyLength , out var publicKey, out var privateKey);
142+
var encryptedData = Encrypt(data, publicKey);
143+
var encryptedDataAsString = Convert.ToHexString(encryptedData);
144+
public void GenerateKeys(int keyLength, out RSAParameters publicKey, out RSAParameters privateKey)
145+
{
146+
using (var rsa = RSA.Create())
147+
{
148+
rsa.KeySize = keyLength;
149+
publicKey = rsa.ExportParameters(includePrivateParameters: false);
150+
privateKey = rsa.ExportParameters(includePrivateParameters: true);
151+
}
152+
}
153+
public byte[] Encrypt(byte[] data, RSAParameters publicKey)
154+
{
155+
using (var rsa = RSA.Create())
156+
{
157+
rsa.ImportParameters(publicKey);
158+
159+
var result = rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
160+
return result;
161+
}
162+
}
163+
public byte[] Decrypt(byte[] data, RSAParameters privateKey)
164+
{
165+
using (var rsa = RSA.Create())
166+
{
167+
rsa.ImportParameters(privateKey);
168+
return rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA256);
169+
}
170+
}
171+
```
172+
173+
另外一种是 `DSA` 算法,用来进行数字签名,因为它只需要校验事否匹配,性能上有优势。
174+
175+
```csharp
176+
var dsa = DSA.Create();
177+
var dataStr = "This is corporate research! Dont read me!";
178+
var data = Encoding.UTF8.GetBytes(dataStr);
179+
var signedData = Sign(dsa, data);
180+
dsa.Dispose();
181+
public byte[] Sign(DSA dsa, byte[] data)
182+
{
183+
if(dsa is null)
184+
throw new NullReferenceException(nameof(dsa));
185+
var result = dsa.SignData(data, HashAlgorithmName.SHA256);
186+
return result;
187+
}
188+
public bool VerifySignature(DSA dsa, byte[] data, byte[] signedData)
189+
{
190+
if (dsa is null)
191+
throw new NullReferenceException(nameof(dsa));
192+
return dsa.VerifyData(data, signedData, HashAlgorithmName.SHA256);
193+
}
194+
```
195+
196+
2、[C# 如何混淆反编译器](https://washi.dev/blog/posts/debugger-proxy-objects/)
197+
198+
这是一篇有意思的文章,作者是一名逆向工程师。我们都知道 `C#` 作为一个包含中间状态的编程语言(IL), 通常使用反编译工具就能得到源代码。那么如何做到混淆反编译工具,让它无法得到源代码呢?
199+
200+
1. Proxy Object
201+
202+
首先通过是 `Proxy Object` 来封装真正的类,而且 C#执行隐式操作符重载,比如创建 `PersonProxy`
203+
204+
```csharp
205+
public sealed class PersonProxy
206+
{
207+
private readonly Person _value;
208+
public Person(Person A_1)
209+
{
210+
_value = A_1;
211+
}
212+
// Implicit conversion operators:
213+
public static implicit operator PersonProxy(Person A_0) => new(A_0);
214+
public static implicit operator Person(PersonProxy A_0) => A_0._value;
215+
}
216+
```
217+
218+
这样任何可以使用 `Person` 的地方都可以使用 `PersonProxy`。同理可以为系统类型进行代理。
219+
220+
2. Display
221+
222+
C# 中的 `DebuggerDisplay` 注解可以方便调试,如何通过反编译工具对程序进行调试,那么可以在 `DebuggerDisplay` 中展示错误信息。
223+
224+
```csharp
225+
using System;
226+
using System.Diagnostics;
227+
namespace System;
228+
[DebuggerDisplay("{Display}")]
229+
public struct Int32
230+
{
231+
[CompilerGenerated]
232+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
233+
private readonly int <0this>k__BackingField; // Renamed by our obfuscator
234+
235+
public Int32(int A_1)
236+
{
237+
this.<0this>k__BackingField = A_1;
238+
}
239+
240+
// Implicit conversion operators:
241+
public static implicit operator int(int A_0) => new(A_0);
242+
public static implicit operator int(int A_0) => A_0.<0this>k__BackingField;
243+
244+
// Random display object:
245+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
246+
public int Display => 31; // Randomly selected by our obfuscator.
247+
}
248+
```
249+
250+
这里 `Display` 使用了一个 `31` 固定值,这样在调试 `Int32` 类型的时候,总是得到一个错误的值。或者可以抛出一个未知的异常。
251+
252+
```csharp
253+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
254+
public string Display
255+
{
256+
get
257+
{
258+
Environment.FailFast("The CLR encountered an internal limitation.");
259+
return null;
260+
}
261+
}
262+
263+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
264+
public string Display => Display
265+
```
266+
267+
亦或者在 Debug 的时候,修改程序的状态
268+
269+
```csharp
270+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
271+
public string Display
272+
{
273+
get
274+
{
275+
// Change the state of the actual object with random values selected by our obfuscator.
276+
// No luck for the reverse engineer to ever find the original values back!
277+
this.<0this>k__BackingField.FirstName = "???";
278+
this.<0this>k__BackingField.LastName = "???";
279+
this.<0this>k__BackingField.CoolnessFactor = 0.0324466228f;
280+
return null;
281+
}
282+
}
283+
```
284+
285+
3C# 构造函数简化
286+
287+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/constructor.png)
288+
289+
```csharp
290+
class Person
291+
{
292+
public int Age { get; set; }
293+
294+
public string Name { get; set; }
295+
296+
public Person(string name, int age) => (Name, Age) = (name, age);
297+
}
298+
```
299+
300+
## 开源项目
301+
302+
1、[bflat](https://github.com/bflattened/bflat)
303+
304+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/bflat.png)
305+
306+
bflat 是一个开源的 `C#` 编译工具,它可以将 `C#` 代码编译成可执行并且 NativeAOT 的执行文件。它和官方的编译工具的区别在于它可以运行在 `UEFI` 中,而且编译出来的文件体积小。
307+
308+
2、[.NET 平台上的 COBOL 编译器](https://github.com/otterkit/otterkit)
309+
310+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/cobol.png)
311+
312+
`Cobol` 是一门古老的编程语言,至今仍然有不少机器任然运行者 Cobol 编写的程序。`.NET` 由于开放性,任何编程语言都可以在上面运行。`otterkit` 即使在 `.NET` 上实现了 `Cobol` 编译器。
313+
314+
3、[QuestPDF](https://github.com/QuestPDF/QuestPDF)
315+
316+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/questpdf.png)
317+
318+
`QuestPDF` 是一个开源的 `.NET` PDF 生成器,它可以按照指定的内容生成相应的 PDF 文件。而且它内置了实时浏览工具,可以动态查看生成的 PDF 内容。
319+
320+
4、[MethodTimer](https://github.com/Fody/MethodTimer)
321+
322+
![image](https://dotnetweeklyimages.blob.core.windows.net/031/methodtimer.png)
323+
324+
我们常常需要测量一个方法执行时间,最直接的方法是使用 `Stopwatch` 测量,比如说
325+
326+
```csharp
327+
var stopwatch = Stopwatch.StartNew();
328+
try
329+
{
330+
// Your method
331+
}
332+
finally
333+
{
334+
stopwatch.Stop();
335+
}
336+
```
337+
338+
这样做肯定是正确的,那么有什么办法简化这个流程呢?就跟 `Python` 中的中装饰器一样呢?`MethodTimer` 库可以做到,它可以通过 `C#` 的 `Source Generation` 方式生成上述的类。而且还提供了 `MethodTimerLogger` 这个类定义耗时操作的日志输出。
339+
340+
```csharp
341+
public static class MethodTimeLogger
342+
{
343+
public static void Log(MethodBase methodBase, long milliseconds, string message)
344+
{
345+
//Do some logging here
346+
}
347+
}
348+
```

docs/images/031/bflat.png

83.4 KB
Loading

docs/images/031/cobol.png

14.9 KB
Loading

docs/images/031/constructor.png

396 KB
Loading

docs/images/031/encryption.png

6.49 MB
Loading

docs/images/031/methodtimer.png

14.1 KB
Loading

docs/images/031/questpdf.png

10.2 KB
Loading

docs/images/031/suvery.png

12.4 KB
Loading

0 commit comments

Comments
 (0)