657 lines
25 KiB
C#
657 lines
25 KiB
C#
using Newtonsoft.Json;
|
|
using Thermo.Active.Model.DTOModels.JobModels;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using static CMS_CORE_Library.Models.DataStructures;
|
|
using static Thermo.Active.Model.Constants;
|
|
|
|
namespace Thermo.Active.Utils
|
|
{
|
|
public static class SupportFunctions
|
|
{
|
|
private static readonly string CMSCONNECT_TOKEN = "59f1qik5PYfiJLiXZ4xZ05pjzx5E9FscQWtj4lmfLKXaF1OAxkvu7ziBzXFBuuVQ";
|
|
|
|
public static SOFTKEY_TYPE GetSoftKeyType(string type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case "softKey_procedure": return SOFTKEY_TYPE.PROCEDURE;
|
|
case "softKey_group": return SOFTKEY_TYPE.GROUP;
|
|
default: return SOFTKEY_TYPE.TOGGLE;
|
|
}
|
|
}
|
|
|
|
public static HEAD_TYPE GetHeadType(string type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case "SPINDLE": return HEAD_TYPE.SPINDLE;
|
|
case "AWJ": return HEAD_TYPE.AWJ;
|
|
default: return HEAD_TYPE.WJ;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Conversion string --> TACT_PARAM_TYPE
|
|
/// </summary>
|
|
/// <param name="strValue"></param>
|
|
/// <returns></returns>
|
|
public static TACT_PARAM_TYPE GetTActParamType(string strValue)
|
|
{
|
|
TACT_PARAM_TYPE answ = TACT_PARAM_TYPE.ND;
|
|
try
|
|
{
|
|
answ = (TACT_PARAM_TYPE)Enum.Parse(typeof(TACT_PARAM_TYPE), strValue);
|
|
}
|
|
catch { }
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Conversion string --> TACT_MBLOCK_TYPE
|
|
/// </summary>
|
|
/// <param name="strValue"></param>
|
|
/// <returns></returns>
|
|
public static TACT_MBLOCK_TYPE GetTActMB_Type(string strValue)
|
|
{
|
|
TACT_MBLOCK_TYPE answ = TACT_MBLOCK_TYPE.ND;
|
|
try
|
|
{
|
|
answ = (TACT_MBLOCK_TYPE)Enum.Parse(typeof(TACT_MBLOCK_TYPE), strValue);
|
|
}
|
|
catch { }
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Conversion string --> TACT_MBLOCK_SECTION
|
|
/// </summary>
|
|
/// <param name="strValue"></param>
|
|
/// <returns></returns>
|
|
public static TACT_MBLOCK_SECTION GetTActMB_Section(string strValue)
|
|
{
|
|
TACT_MBLOCK_SECTION answ = TACT_MBLOCK_SECTION.ND;
|
|
try
|
|
{
|
|
answ = (TACT_MBLOCK_SECTION)Enum.Parse(typeof(TACT_MBLOCK_SECTION), strValue);
|
|
}
|
|
catch { }
|
|
return answ;
|
|
}
|
|
|
|
public static int GetPlcIdFromNcSoftKey(string softKey)
|
|
{
|
|
switch (softKey)
|
|
{
|
|
case "auto": return 1;
|
|
case "edit": return 2;
|
|
case "mdi": return 3;
|
|
case "dnc": return 4;
|
|
case "ref": return 5;
|
|
case "jog": return 6;
|
|
case "jogInc": return 7;
|
|
case "restart": return 8;
|
|
case "teach": return 9;
|
|
case "retract": return 10;
|
|
case "wcsMcs": return 11;
|
|
case "handle": return 12;
|
|
case "reset": return 13;
|
|
case "blk": return 14;
|
|
case "blkDel": return 15;
|
|
case "opStop": return 16;
|
|
case "dryRun": return 17;
|
|
case "prgTest": return 18;
|
|
case "manualHandleInterrupt": return 19;
|
|
case "teachIn": return 20;
|
|
case "incPlane": return 21;
|
|
case "plus": return 22;
|
|
case "minus": return 23;
|
|
case "rapid": return 24;
|
|
case "xOne": return 25;
|
|
case "xTen": return 26;
|
|
case "xHundred": return 27;
|
|
case "xThousand": return 28;
|
|
case "overstroke": return 30;
|
|
case "feedByPass": return 31;
|
|
default: return -1;
|
|
}
|
|
}
|
|
|
|
public static double ConvertInMinutes(double number, MAINTENANCE_UNIT_OF_MEASURE unit)
|
|
{
|
|
switch (unit)
|
|
{
|
|
case MAINTENANCE_UNIT_OF_MEASURE.mm:
|
|
return number;
|
|
|
|
case MAINTENANCE_UNIT_OF_MEASURE.H:
|
|
return number * 60;
|
|
|
|
case MAINTENANCE_UNIT_OF_MEASURE.D:
|
|
return number * (24 * 60);
|
|
|
|
case MAINTENANCE_UNIT_OF_MEASURE.M:
|
|
return (30 * number) * (24 * 60);
|
|
|
|
default:
|
|
return number;
|
|
}
|
|
}
|
|
|
|
public static double ConvertInUmeas(double number, MAINTENANCE_UNIT_OF_MEASURE unit)
|
|
{
|
|
switch (unit)
|
|
{
|
|
case MAINTENANCE_UNIT_OF_MEASURE.mm:
|
|
return number;
|
|
|
|
case MAINTENANCE_UNIT_OF_MEASURE.H:
|
|
return number / 60;
|
|
|
|
case MAINTENANCE_UNIT_OF_MEASURE.D:
|
|
return number / (24 / 60);
|
|
|
|
case MAINTENANCE_UNIT_OF_MEASURE.M:
|
|
return (30 / number) / (24 / 60);
|
|
|
|
default:
|
|
return number;
|
|
}
|
|
}
|
|
|
|
public static void CopyProperties<TParent, TChild>(TParent parent, TChild child) where TParent : class where TChild : class
|
|
{
|
|
var parentProperties = parent.GetType().GetProperties();
|
|
var childProperties = child.GetType().GetProperties();
|
|
|
|
foreach (var parentProperty in parentProperties)
|
|
{
|
|
foreach (var childProperty in childProperties)
|
|
{
|
|
if (parentProperty.Name == childProperty.Name && parentProperty.PropertyType == childProperty.PropertyType)
|
|
{
|
|
childProperty.SetValue(child, parentProperty.GetValue(parent));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static int GetNextId(IEnumerable<int> objIds)
|
|
{
|
|
if (objIds.Count() == 0)
|
|
return 1;
|
|
|
|
return objIds.Max() + 1;
|
|
}
|
|
|
|
public static short GetFirstFreeId(IEnumerable<short> objIds)
|
|
{
|
|
if (objIds.Count() == 0)
|
|
return 1;
|
|
|
|
List<short> listOfPossibleIds = Enumerable.Range(1, objIds.Max() + 1).Select(x => (short)x).ToList();
|
|
|
|
IEnumerable<short> res = listOfPossibleIds.Except(objIds).ToList();
|
|
|
|
if (res.Count() > 0)
|
|
return res.First();
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
public static string GetImageBase64String(string directoryPath, string imageName)
|
|
{
|
|
string fileName = Path.GetFileNameWithoutExtension(imageName);
|
|
foreach (string ext in VALID_IMAGE_EXTENSIONS)
|
|
{
|
|
if (File.Exists(directoryPath + "\\" + fileName + ext))
|
|
{
|
|
// Convert image to a base 64 string
|
|
return "data:image/" + ext + ";base64," + Convert.ToBase64String(File.ReadAllBytes(directoryPath + "\\" + fileName + ext));
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
public static string ExtractBase64ProgIcon(string path)
|
|
{
|
|
if (!File.Exists(path))
|
|
return "";
|
|
|
|
Image im = Icon.ExtractAssociatedIcon(path)?.ToBitmap();
|
|
MemoryStream m = new MemoryStream();
|
|
im.Save(m, ImageFormat.Png);
|
|
return "data:image/png;base64," + Convert.ToBase64String(m.ToArray());
|
|
}
|
|
|
|
public static DTOJobModel UnpackJobAndReadMetadata(string filePath, int processId)
|
|
{
|
|
DTOJobModel job = new DTOJobModel();
|
|
string jobFolderPath = JOB_TMP_DIRECTORY + "\\" + processId + "\\";
|
|
if (!Directory.Exists(jobFolderPath))
|
|
Directory.CreateDirectory(jobFolderPath);
|
|
|
|
// Check if job exists
|
|
if (!File.Exists(filePath))
|
|
return null;
|
|
|
|
EmptyFolder(jobFolderPath);
|
|
|
|
using (ZipArchive zipExtractor = ZipFile.OpenRead(filePath))
|
|
{
|
|
// Setup main job fields
|
|
job.Name = Path.GetFileName(filePath);
|
|
job.LastEditTimestamp = new FileInfo(filePath).LastAccessTime;
|
|
|
|
foreach (ZipArchiveEntry entry in zipExtractor.Entries)
|
|
{
|
|
// Extract file
|
|
entry.ExtractToFile(jobFolderPath + entry.Name, true);
|
|
|
|
// Get main program content
|
|
if (entry.Name.Equals(JOB_MAIN_FILENAME, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
using (var reader = new StreamReader(entry.Open()))
|
|
job.IsoMainProgram = (reader.ReadToEnd());
|
|
}
|
|
// Read images
|
|
else if (VALID_IMAGE_EXTENSIONS.Contains(Path.GetExtension(entry.Name).ToLower()))
|
|
{
|
|
var bytes = default(byte[]);
|
|
// Populate metadata
|
|
using (var memstream = new MemoryStream())
|
|
{
|
|
entry.Open().CopyTo(memstream);
|
|
bytes = memstream.ToArray();
|
|
job.Metadata.Generics.Images.Add(new DTOImageParamModel()
|
|
{
|
|
Name = Path.GetFileNameWithoutExtension(entry.Name),
|
|
Base64 = "data:image/" + Path.GetExtension(entry.Name).ToLower().TrimStart('.') + ";base64," + Convert.ToBase64String(bytes)
|
|
});
|
|
}
|
|
}
|
|
// Read metadata
|
|
else if (entry.Name.Equals(JOB_METADATA_FILENAME, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
DTOMetadataFieldsModel metasFromFile = new DTOMetadataFieldsModel();
|
|
|
|
using (var reader = new StreamReader(entry.Open()))
|
|
{
|
|
metasFromFile = JsonConvert.DeserializeObject<DTOMetadataFieldsModel>(reader.ReadToEnd());
|
|
if (metasFromFile == null)
|
|
{
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
job.Metadata.Generics.Description = metasFromFile.Description;
|
|
job.Metadata.Generics.ExecutionTime = metasFromFile.ExecutionTime;
|
|
job.Metadata.Customs = metasFromFile.Customs;
|
|
}
|
|
}
|
|
}
|
|
// Consider other file as part program
|
|
else
|
|
{
|
|
job.PartPrograms.Add(jobFolderPath + entry.Name);
|
|
}
|
|
}
|
|
|
|
return job;
|
|
}
|
|
}
|
|
|
|
public static void EmptyFolder(string path)
|
|
{
|
|
DirectoryInfo di = new DirectoryInfo(path);
|
|
foreach (FileInfo file in di.GetFiles())
|
|
file.Delete();
|
|
foreach (DirectoryInfo dir in di.GetDirectories())
|
|
dir.Delete(true);
|
|
}
|
|
|
|
public static bool IsValidJob(string filePath)
|
|
{
|
|
if (!File.Exists(filePath))
|
|
return false;
|
|
|
|
try
|
|
{
|
|
using (var archive = ZipFile.OpenRead(filePath))
|
|
{
|
|
// Find key files
|
|
List<ZipArchiveEntry> files = archive
|
|
.Entries
|
|
.Where(x => x.FullName == JOB_MAIN_FILENAME || x.FullName == JOB_METADATA_FILENAME)
|
|
.ToList();
|
|
// if there aren't both
|
|
if (files.Count() < 2)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public static DTOJobModel ReadExtractedJobMetadata(int processId)
|
|
{
|
|
string filePath = JOB_TMP_DIRECTORY + "\\" + processId + "\\";
|
|
if (!Directory.Exists(filePath))
|
|
return null;
|
|
|
|
// Setup main Fields
|
|
DTOJobModel jobData = new DTOJobModel()
|
|
{
|
|
Name = Path.GetFileName(filePath),
|
|
LastEditTimestamp = new FileInfo(filePath).LastAccessTime
|
|
};
|
|
|
|
DirectoryInfo di = new DirectoryInfo(filePath);
|
|
foreach (FileInfo file in di.GetFiles())
|
|
{
|
|
// Get main program content
|
|
if (file.Name.Equals(JOB_MAIN_FILENAME, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
jobData.IsoMainProgram = (File.ReadAllText(file.FullName));
|
|
}
|
|
// Get images content without extract files
|
|
else if (VALID_IMAGE_EXTENSIONS.Contains(Path.GetExtension(file.Name).ToLower()))
|
|
{
|
|
byte[] bytes = File.ReadAllBytes(file.FullName);
|
|
jobData.Metadata.Generics.Images.Add(new DTOImageParamModel()
|
|
{
|
|
Name = file.Name,
|
|
Base64 = "data:image/" + Path.GetExtension(file.Name).ToLower().TrimStart('.') + ";base64," + Convert.ToBase64String(bytes)
|
|
});
|
|
}
|
|
// Metadata
|
|
else if (file.Name.Equals(JOB_METADATA_FILENAME, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
DTOMetadataFieldsModel metasFromFile = new DTOMetadataFieldsModel();
|
|
|
|
metasFromFile = JsonConvert
|
|
.DeserializeObject<DTOMetadataFieldsModel>
|
|
(File.ReadAllText(file.FullName));
|
|
|
|
if (metasFromFile == null)
|
|
return null;
|
|
else
|
|
{
|
|
jobData.Metadata.Generics.Description = metasFromFile.Description;
|
|
jobData.Metadata.Generics.ExecutionTime = metasFromFile.ExecutionTime;
|
|
jobData.Metadata.Customs = metasFromFile.Customs;
|
|
}
|
|
}
|
|
}
|
|
|
|
return jobData;
|
|
}
|
|
|
|
|
|
public static SCADA_MEM_TYPE GetMemTypeFromString(string memType)
|
|
{
|
|
memType = memType.ToUpper();
|
|
switch (memType)
|
|
{
|
|
case "BOOL":
|
|
return SCADA_MEM_TYPE.BOOL;
|
|
|
|
case "BYTE":
|
|
return SCADA_MEM_TYPE.BYTE;
|
|
|
|
case "WORD":
|
|
return SCADA_MEM_TYPE.WORD;
|
|
|
|
case "INT":
|
|
return SCADA_MEM_TYPE.INT;
|
|
|
|
case "REAL":
|
|
return SCADA_MEM_TYPE.REAL;
|
|
|
|
default:
|
|
return SCADA_MEM_TYPE.BOOL;
|
|
}
|
|
}
|
|
|
|
public static DateTime GetLinkerTime(Assembly assembly, TimeZoneInfo target = null)
|
|
{
|
|
var filePath = assembly.Location;
|
|
const int c_PeHeaderOffset = 60;
|
|
const int c_LinkerTimestampOffset = 8;
|
|
|
|
var buffer = new byte[2048];
|
|
|
|
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
|
stream.Read(buffer, 0, 2048);
|
|
|
|
var offset = BitConverter.ToInt32(buffer, c_PeHeaderOffset);
|
|
var secondsSince1970 = BitConverter.ToInt32(buffer, offset + c_LinkerTimestampOffset);
|
|
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
|
|
var linkTimeUtc = epoch.AddSeconds(secondsSince1970);
|
|
|
|
var tz = target ?? TimeZoneInfo.Local;
|
|
var localTime = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tz);
|
|
|
|
return localTime;
|
|
}
|
|
|
|
public static string GetSoftwareVersionAndBuildDate()
|
|
{
|
|
Version v = Assembly.GetEntryAssembly()?.GetName().Version;
|
|
if (v != null)
|
|
{
|
|
// Get first 2 number of the version
|
|
var version = v.ToString().Split('.').Take(3).ToArray();
|
|
|
|
string betaString = IS_BETA ? " BETA " : " ";
|
|
|
|
// Get Server version
|
|
return $"{string.Join(".", version)}" +
|
|
betaString +
|
|
$"({GetLinkerTime(Assembly.GetEntryAssembly(), null).ToString("d")}" +
|
|
$")";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
|
|
public static Boolean DecodeCMSConnectGatewayLogin(string encryptedString, out string login, out string password)
|
|
{
|
|
login = "";
|
|
password = "";
|
|
|
|
//Check if is null
|
|
if (String.IsNullOrEmpty(encryptedString))
|
|
return false;
|
|
|
|
//Decode it
|
|
String decodedLogin = StringCipher.Decrypt(encryptedString, CMSCONNECT_TOKEN);
|
|
|
|
//Check if contains the Space
|
|
if (!decodedLogin.Contains(" "))
|
|
return false;
|
|
|
|
//Split it and check
|
|
String[] tempLogin = decodedLogin.Split(' ');
|
|
if (tempLogin.Length != 2)
|
|
return false;
|
|
|
|
//Set the variable
|
|
login = tempLogin[0];
|
|
password = tempLogin[1];
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
public static Boolean EncodeCMSConnectGatewayLogin(out string encryptedString, string login, string password)
|
|
{
|
|
encryptedString = "";
|
|
|
|
//Check if contains the Space
|
|
if (String.IsNullOrEmpty(login) || login.Contains(" "))
|
|
return false;
|
|
|
|
//Check if contains the Space
|
|
if (String.IsNullOrEmpty(password) || password.Contains(" "))
|
|
return false;
|
|
|
|
encryptedString = StringCipher.Encrypt(login + " " + password, CMSCONNECT_TOKEN);
|
|
return true;
|
|
}
|
|
|
|
public static string ConvertIntToAsciiString(int integer)
|
|
{
|
|
string outputString = "";
|
|
for (int i = 3; i >= 0; i--)
|
|
{
|
|
outputString += (char)((byte)(integer >> (8 * i)));
|
|
}
|
|
|
|
return outputString;
|
|
}
|
|
|
|
public static int ConvertAsciiStringToInt(string asciiString)
|
|
{
|
|
int number = 0;
|
|
for (int i = 1; i <= asciiString.Count(); i++)
|
|
number += asciiString[asciiString.Count() - i] << (8 * (i - 1));
|
|
|
|
return number;
|
|
}
|
|
|
|
public static void ConvertStringMachineNumberIntoNumber(string machineNumber, out bool containsLetters, out int intMachineVal)
|
|
{
|
|
intMachineVal = 0;
|
|
containsLetters = Regex.IsMatch(machineNumber, @".*?[a-zA-Z].*?");
|
|
if (string.IsNullOrEmpty(machineNumber))
|
|
{
|
|
machineNumber = "0000";
|
|
}
|
|
if (containsLetters)
|
|
// Convert ASCII string to a single INT
|
|
intMachineVal = SupportFunctions.ConvertAsciiStringToInt(machineNumber);
|
|
else
|
|
// Convert string of digits to a INT
|
|
intMachineVal = int.Parse(machineNumber);
|
|
}
|
|
|
|
//----- Chipher Private Class ---------------------------------
|
|
#region Chipher_Private_Class
|
|
|
|
private 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 = 256;
|
|
|
|
// 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 = Generate256BitsOfRandomEntropy();
|
|
var ivStringBytes = Generate256BitsOfRandomEntropy();
|
|
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
|
|
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
|
|
{
|
|
var keyBytes = password.GetBytes(Keysize / 8);
|
|
using (var symmetricKey = new RijndaelManaged())
|
|
{
|
|
symmetricKey.BlockSize = 256;
|
|
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] + [32 bytes of IV] + [n bytes of CipherText]
|
|
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
|
|
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
|
|
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
|
|
// Get the IV bytes by extracting the next 32 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 = new RijndaelManaged())
|
|
{
|
|
symmetricKey.BlockSize = 256;
|
|
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[] Generate256BitsOfRandomEntropy()
|
|
{
|
|
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
|
|
using (var rngCsp = new RNGCryptoServiceProvider())
|
|
{
|
|
// Fill the array with cryptographically secure random bytes.
|
|
rngCsp.GetBytes(randomBytes);
|
|
}
|
|
return randomBytes;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |