Skip to content

Commit

Permalink
StringCipher class
Browse files Browse the repository at this point in the history
  • Loading branch information
Ciuraru committed Nov 8, 2022
1 parent e789708 commit b2b3d55
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 7 deletions.
3 changes: 3 additions & 0 deletions ElegantRecorder/ElegantOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class ElegantOptions
public string ExePath { get; set; }
[JsonIgnore]
public string CurrRecName { get; set; }
[JsonIgnore]
public bool Encrypted { get; set; }

public ElegantOptions()
{
Expand All @@ -44,6 +46,7 @@ public ElegantOptions()
FormHeight = 350;
DataGridHeight = 155;
CurrRecName = "";
Encrypted = false;
}

public void Save(string FilePath)
Expand Down
27 changes: 20 additions & 7 deletions ElegantRecorder/Options.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ElegantRecorder/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public Options(ElegantRecorder elegantRecorder)
buttonBrowseExe.Enabled = checkBoxRestrictToExe.Checked;

comboBoxSpeed.SelectedItem = App.ElegantOptions.PlaybackSpeed;
checkBoxEncrypted.Checked = App.ElegantOptions.Encrypted;
checkBoxRestrictToExe.Checked = App.ElegantOptions.RestrictToExe;
textBoxExePath.Text = App.ElegantOptions.ExePath;

Expand All @@ -53,6 +54,7 @@ public void SaveOptions()
App.ElegantOptions.StopHotkey = stopHotkeyData;

App.ElegantOptions.PlaybackSpeed = comboBoxSpeed.SelectedItem as string;
App.ElegantOptions.Encrypted = checkBoxEncrypted.Checked;
App.ElegantOptions.RestrictToExe = checkBoxRestrictToExe.Checked;
App.ElegantOptions.ExePath = textBoxExePath.Text;

Expand Down
5 changes: 5 additions & 0 deletions ElegantRecorder/Recording.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class Recording

public string Tag { get; set; }
public string PlaybackSpeed { get; set; }
public bool Encrypted { get; set; }
public bool RestrictToExe { get; set; }
public string ExePath { get; set; }
public UIAction[] UIActions { get; set; }
Expand All @@ -35,6 +36,7 @@ public Recording(ElegantRecorder app, string name)
Tag = DefaultTag;

PlaybackSpeed = "Normal";
Encrypted = false;
RestrictToExe = false;
ExePath = "";

Expand All @@ -49,13 +51,15 @@ private void SyncAppOptions(bool direction)
if (direction)
{
App.ElegantOptions.PlaybackSpeed = PlaybackSpeed;
App.ElegantOptions.Encrypted = Encrypted;
App.ElegantOptions.RestrictToExe = RestrictToExe;
App.ElegantOptions.ExePath = ExePath;
App.ElegantOptions.CurrRecName = Name;
}
else
{
PlaybackSpeed = App.ElegantOptions.PlaybackSpeed;
Encrypted = App.ElegantOptions.Encrypted;
RestrictToExe = App.ElegantOptions.RestrictToExe;
ExePath = App.ElegantOptions.ExePath;
Name = App.ElegantOptions.CurrRecName;
Expand Down Expand Up @@ -111,6 +115,7 @@ public void Save()

stream.Write("\"Tag\":" + JsonSerializer.Serialize(DefaultTag) + ",");
stream.Write("\"PlaybackSpeed\":" + JsonSerializer.Serialize(PlaybackSpeed) + ",");
stream.Write("\"Encrypted\":" + JsonSerializer.Serialize(Encrypted) + ",");
stream.Write("\"RestrictToExe\":" + JsonSerializer.Serialize(RestrictToExe) + ",");
stream.Write("\"ExePath\":" + JsonSerializer.Serialize(ExePath) + ",");

Expand Down
105 changes: 105 additions & 0 deletions ElegantRecorder/StringCipher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace ElegantRecorder
{
//source: https://stackoverflow.com/questions/69911084/problem-updating-to-net-6-encrypting-string
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 128;

// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;

public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate128BitsOfRandomEntropy();
var ivStringBytes = Generate128BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = Aes.Create())
{
symmetricKey.BlockSize = 128;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}

public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [16 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 16 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 16 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();

using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = Aes.Create())
{
symmetricKey.BlockSize = 128;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}

private static byte[] Generate128BitsOfRandomEntropy()
{
var randomBytes = new byte[16]; // 16 Bytes will give us 128 bits.
using (var rngCsp = RandomNumberGenerator.Create())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
}

0 comments on commit b2b3d55

Please sign in to comment.