初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace PCL.Core.Utils.Encryption;
|
||||
|
||||
public sealed class ChaCha20Poly1305Provider : IEncryptionProvider
|
||||
{
|
||||
public static ChaCha20Poly1305Provider Instance { get; } = new();
|
||||
|
||||
private const int NonceSize = 12; // 96-bit nonce for ChaCha20Poly1305
|
||||
private const int TagSize = 16; // 128-bit authentication tag
|
||||
private const int KeySize = 32; // 256-bit key
|
||||
private const int SaltSize = 16; // 128-bit salt for HKDF
|
||||
|
||||
public byte[] Encrypt(ReadOnlySpan<byte> data, ReadOnlySpan<byte> key)
|
||||
{
|
||||
// Generate random salt, nonce and the tag
|
||||
var salt = new byte[SaltSize];
|
||||
var nonce = new byte[NonceSize];
|
||||
var tag = new byte[TagSize];
|
||||
RandomNumberGenerator.Fill(salt);
|
||||
RandomNumberGenerator.Fill(nonce);
|
||||
RandomNumberGenerator.Fill(tag);
|
||||
|
||||
// Derive key using the salt
|
||||
Span<byte> outputKey = stackalloc byte[KeySize];
|
||||
_DeriveKey(key, salt, outputKey);
|
||||
using var chacha = new ChaCha20Poly1305(outputKey);
|
||||
|
||||
// Prepare output arrays
|
||||
var ciphertext = new byte[data.Length];
|
||||
|
||||
// Perform encryption
|
||||
chacha.Encrypt(nonce, data, ciphertext, tag);
|
||||
|
||||
// Make the encryption data: salt + nonce + tag + ciphertext
|
||||
var result = new byte[SaltSize + NonceSize + ciphertext.Length + TagSize];
|
||||
var resultSpan = result.AsSpan();
|
||||
|
||||
salt.CopyTo(resultSpan[..SaltSize]);
|
||||
nonce.CopyTo(resultSpan.Slice(SaltSize, NonceSize));
|
||||
tag.CopyTo(resultSpan.Slice(SaltSize + NonceSize, TagSize));
|
||||
ciphertext.CopyTo(resultSpan.Slice(SaltSize + NonceSize + TagSize, ciphertext.Length));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] Decrypt(ReadOnlySpan<byte> data, ReadOnlySpan<byte> key)
|
||||
{
|
||||
// Verify minimum data length
|
||||
if (data.Length < SaltSize + NonceSize + TagSize)
|
||||
throw new ArgumentException("Invalid encrypted data length");
|
||||
|
||||
// Encryption data: salt + nonce + tag + ciphertext
|
||||
var salt = data[..SaltSize];
|
||||
var nonce = data.Slice(SaltSize, NonceSize);
|
||||
var tag = data.Slice(SaltSize + NonceSize, TagSize);
|
||||
var ciphertext = data[(SaltSize + NonceSize + TagSize)..];
|
||||
|
||||
// Derive key using the extracted salt
|
||||
Span<byte> outputKey = stackalloc byte[KeySize];
|
||||
_DeriveKey(key, salt, outputKey);
|
||||
using var chacha = new ChaCha20Poly1305(outputKey);
|
||||
|
||||
// Perform decryption
|
||||
var plaintext = new byte[ciphertext.Length];
|
||||
chacha.Decrypt(nonce, ciphertext, tag, plaintext);
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
private static readonly byte[] _Info = "PCL.Core.Utils.Encryption.ChaCha20"u8.ToArray();
|
||||
private static void _DeriveKey(ReadOnlySpan<byte> ikm, ReadOnlySpan<byte> salt, Span<byte> outputKey)
|
||||
{
|
||||
HKDF.DeriveKey(
|
||||
HashAlgorithmName.SHA256,
|
||||
ikm,
|
||||
outputKey,
|
||||
salt,
|
||||
_Info.AsSpan());
|
||||
}
|
||||
|
||||
public bool IsSupported { get => ChaCha20Poly1305.IsSupported; }
|
||||
}
|
||||
Reference in New Issue
Block a user