Files
PowerToys/src/modules/MouseWithoutBorders/App/Class/Common.Encryption.cs
Jeremy Sinclair b2b2856e52 🚧 [Dev][Build] .NET 8 Upgrade (#28655)
* Upgraded projects to target .NET 8

* Updated .NET runtime package targets to use latest .NET 8 build

* Updated PowerToys Interop to target .NET 8

* Switch to use ArgumentNullException.ThrowIfNull

* ArgumentNullException.ThrowIfNull for CropAndLockViewModel

* Switching to ObjectDisposedException.ThrowIf

* Upgrade System.ComponentModel.Composition to 8.0

* ArgumentNullException.ThrowIfNull in Helper

* Switch to StartsWith using StringComparison.Ordinal

* Disabled CA1859, CA1716, SYSLIB1096 analyzers

* Update RIDs to reflect breaking changes in .NET 8

* Updated Microsoft NuGet packages to RC1

* Updated Analyzer package to latest .NET 8 preview package

* CA1854: Use TryGetValue instead of ContainsKey

* [Build] Update TFM to .NET 8 for publish profiles

* [Analyzers] Remove CA1309, CA1860-CA1865, CA1869, CA2208 from warning.

* [Analyzers] Fix for C26495

* [Analyzers] Disable CS1615, CS9191

* [CI] Target .NET 8 in YAML

* [CI] Add .NET preview version flag temporarily.

* [FileLocksmith] Update TFM to .NET 8

* [CI] Switch to preview agent

* [CI] Update NOTICE.md

* [CI] Update Release to target .NET 8 and use Preview agent

* [Analyzers] Disable CA1854

* Fix typo

* Updated Microsoft.CodeAnalysis.NetAnalyzers to latest preview

Updated packages to rc2

* [Analyzers][CPP] Turn off warning for 5271

* [Analyzers][CPP] Turn off warning for 26493

* [KeyboardListener] Add mutex include to resolve error

* [PT Run][Folder] Use static SearchValues to resolve CA1870

* [PowerLauncher] Fix TryGetValue

* [MouseJumpSettings] Use ArgumentNullException.ThrowIfNull

* [Build] Disable parallel dotnet tool restore

* [Build] No cache of dotnet tool packages

* [Build] Temporarily move .NET 8 SDK task before XAML formatting

* [Build][Temp] Try using .NET 7 prior to XAML formatting and then switch to .NET 8 after

* [Build] Use .NET 6 for XAML Styler

* [CI] Updated NOTICE.md

* [FancyZones] Update TFM to .NET 8

* [EnvVar] Update TFM to .NET 8 and update RID

* [EnvVar] Use ArgumentNullException.ThrowIfNull

* [Dev] Updated packages to .NET 8 RTM version

* [Dev] Updated Microsoft.CodeAnalysis.NetAnalyzers to latest

* [CI] Updated NOTICE.md with latest package versions

* Fix new utility target fameworks and runtimeids

* Don't use preview images anymore

* [CI] Add script to update VCToolsVersion environment variable

* [CI] Add Step to Verify VCToolsVersion

* [CI] Use latest flag for vswhere to set proper VCToolsVersion

* Add VCToolsVersion checking to release.yml

* Remove net publishing from local/ PR CI builds

* Revert "Remove net publishing from local/ PR CI builds"

This reverts commit f469778996.

* Only publish necessary projects

* Add verbosity to release pipelines builds of PowerTOys

* Set VCToolsVersion for publish.cmd when called from installer

* [Installer] Moved project publish logic to MSBuild Task

* [CI] Revert using publish.cmd

* [CI] Set VCToolsVersion and unset ClearDevCommandPromptEnvVars property

* Installer publishes for x64 too

* Revert "Add verbosity to release pipelines builds of PowerTOys"

This reverts commit 654d4a7f78.

* [Dev] Update CodeAnalysis library to non-preview package

* Remove unneeded warning removal

* Fix Notice.md

* Rename VCToolsVersion file and task name

* Remove unneeded mutex header include

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2023-11-22 12:46:59 -05:00

243 lines
7.7 KiB
C#

// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// <summary>
// Encrypt/decrypt implementation.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace MouseWithoutBorders
{
internal partial class Common
{
private static SymmetricAlgorithm symAl;
private static string myKey;
private static uint magicNumber;
private static Random ran = new(); // Used for non encryption related functionality.
internal const int SymAlBlockSize = 16;
/// <summary>
/// This is used for the first encryption block, the following blocks will be combined with the cipher text of the previous block.
/// Thus identical blocks in the socket stream would be encrypted to different cipher text blocks.
/// The first block is a handshake one containing random data.
/// Related Unit Test: TestEncryptDecrypt
/// </summary>
internal static readonly string InitialIV = ulong.MaxValue.ToString(CultureInfo.InvariantCulture);
internal static Random Ran
{
get => Common.ran ??= new Random();
set => Common.ran = value;
}
internal static uint MagicNumber
{
get => Common.magicNumber;
set => Common.magicNumber = value;
}
internal static string MyKey
{
get => Common.myKey;
set
{
if (Common.myKey != value)
{
Common.myKey = value;
_ = Task.Factory.StartNew(
() => Common.GenLegalKey(),
System.Threading.CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default); // Cache the key to improve UX.
}
}
}
internal static string KeyDisplayedText(string key)
{
string displayedValue = string.Empty;
int i = 0;
do
{
int length = Math.Min(4, key.Length - i);
displayedValue += string.Concat(key.AsSpan(i, length), " ");
i += 4;
}
while (i < key.Length - 1);
return displayedValue.Trim();
}
internal static bool GeneratedKey { get; set; }
internal static bool KeyCorrupted { get; set; }
internal static void InitEncryption()
{
try
{
if (symAl == null)
{
#pragma warning disable SYSLIB0021 // No proper replacement for now
symAl = new AesCryptoServiceProvider();
#pragma warning restore SYSLIB0021
symAl.KeySize = 256;
symAl.BlockSize = SymAlBlockSize * 8;
symAl.Padding = PaddingMode.Zeros;
symAl.Mode = CipherMode.CBC;
symAl.GenerateIV();
}
}
catch (Exception e)
{
Log(e);
}
}
private static readonly ConcurrentDictionary<string, byte[]> LegalKeyDictionary = new(StringComparer.OrdinalIgnoreCase);
internal static byte[] GenLegalKey()
{
byte[] rv;
string myKey = Common.MyKey;
if (!LegalKeyDictionary.TryGetValue(myKey, out byte[] value))
{
Rfc2898DeriveBytes key = new(
myKey,
Common.GetBytesU(InitialIV),
50000,
HashAlgorithmName.SHA512);
rv = key.GetBytes(32);
_ = LegalKeyDictionary.AddOrUpdate(myKey, rv, (k, v) => rv);
}
else
{
rv = value;
}
return rv;
}
private static byte[] GenLegalIV()
{
string st = InitialIV;
int ivLength = symAl.IV.Length;
if (st.Length > ivLength)
{
st = st[..ivLength];
}
else if (st.Length < ivLength)
{
st = st.PadRight(ivLength, ' ');
}
return GetBytes(st);
}
internal static Stream GetEncryptedStream(Stream encryptedStream)
{
ICryptoTransform encryptor;
encryptor = symAl.CreateEncryptor(GenLegalKey(), GenLegalIV());
return new CryptoStream(encryptedStream, encryptor, CryptoStreamMode.Write);
}
internal static Stream GetDecryptedStream(Stream encryptedStream)
{
ICryptoTransform decryptor;
decryptor = symAl.CreateDecryptor(GenLegalKey(), GenLegalIV());
return new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read);
}
internal static uint Get24BitHash(string st)
{
if (string.IsNullOrEmpty(st))
{
return 0;
}
byte[] bytes = new byte[PACKAGE_SIZE];
for (int i = 0; i < PACKAGE_SIZE; i++)
{
if (i < st.Length)
{
bytes[i] = (byte)st[i];
}
}
var hash = SHA512.Create();
byte[] hashValue = hash.ComputeHash(bytes);
for (int i = 0; i < 50000; i++)
{
hashValue = hash.ComputeHash(hashValue);
}
Common.LogDebug(string.Format(CultureInfo.CurrentCulture, "magic: {0},{1},{2}", hashValue[0], hashValue[1], hashValue[^1]));
hash.Clear();
return (uint)((hashValue[0] << 23) + (hashValue[1] << 16) + (hashValue[^1] << 8) + hashValue[2]);
}
internal static string GetDebugInfo(string st)
{
return string.IsNullOrEmpty(st) ? st : ((byte)(Common.GetBytesU(st).Sum(value => value) % 256)).ToString(CultureInfo.InvariantCulture);
}
internal static string CreateDefaultKey()
{
return CreateRandomKey();
}
private const int PW_LENGTH = 16;
public static string CreateRandomKey()
{
// Not including characters like "'`O0& since they are confusing to users.
string[] chars = new[] { "abcdefghjkmnpqrstuvxyz", "ABCDEFGHJKMNPQRSTUVXYZ", "123456789", "~!@#$%^*()_-+=:;<,>.?/\\|[]" };
char[][] charactersUsedForKey = chars.Select(charset => Enumerable.Range(0, charset.Length - 1).Select(i => charset[i]).ToArray()).ToArray();
byte[] randomData = new byte[1];
string key = string.Empty;
do
{
foreach (string set in chars)
{
randomData = RandomNumberGenerator.GetBytes(1);
key += set[randomData[0] % set.Length];
if (key.Length >= PW_LENGTH)
{
break;
}
}
}
while (key.Length < PW_LENGTH);
return key;
}
internal static bool IsKeyValid(string key, out string error)
{
error = string.IsNullOrEmpty(key) || key.Length < 16
? "Key must have at least 16 characters in length (spaces are discarded). Key must be auto generated in one of the machines."
: null;
return error == null;
}
}
}