wabbajack/Wabbajack.Services.OSIntegrated/ProtectedData.cs

84 lines
3.0 KiB
C#
Raw Permalink Normal View History

2022-10-08 03:43:44 +00:00
using System;
2021-09-27 12:42:46 +00:00
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using DeviceId;
using Wabbajack.Common;
using Wabbajack.Hashing.xxHash64;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
2021-10-23 16:51:17 +00:00
namespace Wabbajack.Services.OSIntegrated;
public static class ProtectedData
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
private static readonly Task<byte[]> _deviceKey;
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
static ProtectedData()
{
2021-12-17 23:40:45 +00:00
2021-10-23 16:51:17 +00:00
_deviceKey = Task.Run(async () =>
2021-09-27 12:42:46 +00:00
{
2021-12-17 23:40:45 +00:00
var id = Encoding.UTF8.GetBytes(KnownFolders.AppDataLocal.ToString());
2021-10-23 16:51:17 +00:00
var hash1 = await id.Hash();
var hash2 = new Hash((ulong) hash1 ^ 42);
var hash3 = new Hash((ulong) hash1 ^ (ulong.MaxValue - 42));
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
var hashes = new[] {hash1.ToArray(), hash2.ToArray(), hash3.ToArray()}.ConcatArrays();
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
return hashes;
});
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async ValueTask<Stream> Protect(this Stream outStream, string key)
{
var encryptor = TripleDES.Create()
.CreateEncryptor(await _deviceKey, (await Encoding.UTF8.GetBytes(key).Hash()).ToArray());
return new CryptoStream(outStream, encryptor, CryptoStreamMode.Write);
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public static async ValueTask<Stream> UnProtect(this Stream inStream, string key)
{
var encryptor = TripleDES.Create()
.CreateDecryptor(await _deviceKey, (await Encoding.UTF8.GetBytes(key).Hash()).ToArray());
return new CryptoStream(inStream, encryptor, CryptoStreamMode.Read);
}
public static async Task AsEncryptedJsonFile<T>(this T obj, AbsolutePath destination)
{
destination.Parent.CreateDirectory();
await using var fs = destination.Open(FileMode.Create, FileAccess.Write, FileShare.None);
await using var enc = await fs.Protect(destination.FileName.ToString());
await JsonSerializer.SerializeAsync(enc, obj);
await enc.FlushAsync();
}
public static async Task AsEncryptedDataFile(this byte[] obj, AbsolutePath destination)
{
destination.Parent.CreateDirectory();
await using var fs = destination.Open(FileMode.Create, FileAccess.Write, FileShare.None);
await using var enc = await fs.Protect(destination.FileName.ToString());
await enc.WriteAsync(obj);
}
public static async Task<T?> FromEncryptedJsonFile<T>(this AbsolutePath destination)
{
if (!destination.FileExists()) return default;
await using var fs = destination.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
await using var enc = await fs.UnProtect(destination.FileName.ToString());
return await JsonSerializer.DeserializeAsync<T>(enc);
}
public static async Task<byte[]> FromEncryptedDataFile(this AbsolutePath destination)
{
2022-10-08 03:43:44 +00:00
if (!destination.FileExists()) return Array.Empty<byte>();
2021-10-23 16:51:17 +00:00
await using var fs = destination.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
await using var enc = await fs.UnProtect(destination.FileName.ToString());
return await enc.ReadAllAsync();
2021-09-27 12:42:46 +00:00
}
}