System.Security.Cryptography
Będę wdzięczny za podpowiedź który z algorytmów będzie najbardziej wydajny / użyteczny dla dużej ilości krótkich łańcuchów. Powiedzmy do 100 znaków. I jeśli to ma znaczenie to chodzi o szyfrowanie w SQlite.
Jeśli chodzi o szyfr blokowy, to wszystkie algorytmy implementuje się na jeden sposób, jedynie w dwóch miejscach masz enum, jeden to rodzaj algorytmu, drugi to tryb szyfru blokowego.
Kombinacji nie ma wiele, więc to żaden problem samemu sobie sprawdzić na ciągu pseudolosowym.
Dzięki za podpowiedź. Dopiero zaczynam z kryptografią więc każda wskazówka jest pomocna.
Trochę opracowałem temat. Na podstawie https://blogprogramisty.net/bezpieczenstwo-w-aplikacjach-c-podstawy-i-nie-tylko-czesc-i/ oraz https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-6.0 wybrałem szyfrowanie symetryczne AES. A to efekt:
public class Szyfrowanie
{
// pola testowe
private static byte[] IV = { 0x01, 0x01, 0x03, 0x04, 0x13, 0x06, 0x07, 0x08, 0x16, 0x10, 0x15, 0x12, 0x13, 0x14, 0x07, 0x15 };
private static byte[] publicKey = { 0x01, 0x01, 0x03, 0x04, 0x13, 0x06, 0x07, 0x08, 0x16, 0x10, 0x15, 0x12, 0x13, 0x14, 0x07, 0x15 };
public string SzyfrowanieIO(string input)
{
string output;
Szyfracja szyfracja = new Szyfracja(input);
output = szyfracja.output;
return output;
}
public string DeszyfrowanieIO(string input)
{
string output;
Deszyfracja deszyfracja = new Deszyfracja(input);
output = deszyfracja.output;
return output;
}
private class Szyfracja
{
public string output { get; private set; }
public Szyfracja(string inputText)
{
output = MetodaWstepna(inputText);
}
private string MetodaWstepna(string input)
{
string output;
using (Aes myAes = Aes.Create())
{
output = Convert.ToBase64String(EncryptStringToBytes_Aes(input, publicKey, IV));
}
return output;
}
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
}
private class Deszyfracja
{
public string output { get; private set; }
public Deszyfracja(string inputText)
{
output = MetodaWstepna(inputText);
}
private string MetodaWstepna(string input)
{
string output;
byte[] miidlebyte = Convert.FromBase64String(input);
using (Aes myAes = Aes.Create())
{
output = (DecryptStringFromBytes_Aes(miidlebyte, publicKey, IV));
}
return output;
}
static string DecryptStringFromBytes_Aes(byte[]? cipherText, byte[] Key, byte[] IV)
{
//if (cipherText == null || cipherText.Length <= 0)
// throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
string plaintext = null;
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
}
}
Jak pisałem wcześniej dopiero zaczynam z kryptografią więc proszę o wskazówki jeśli w tym zapisie znajduje się jakiś zasadniczy błąd.
Co prawda jest to przetestowane i działa ale zdaję sobie sprawę że ciężko przewidzieć wszystkie wyjątki.
Generalnie zbytnio rozmazujesz:
public string DeszyfrowanieIO(string input)
{
string output;
Deszyfracja deszyfracja = new Deszyfracja(input);
output = deszyfracja.output;
return output;
}
VS
public string DeszyfrowanieIO(string input)
{
return new Deszyfracja(input).output;
}
Po kiego ci private string MetodaWstepna(string input)
?
Aby w niej utworzyć zbędnego Aes
'a?
Zmień: static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
na: static string SzyfrowanieIO(string plainText, byte[] Key, byte[] IV)
oraz: static string DecryptStringFromBytes_Aes(byte[]? cipherText, byte[] Key, byte[] IV)
na: static string DeszyfrowanieIO(string cipherText, byte[] Key, byte[] IV)
umieszczając: Convert.ToBase64String()
oraz Convert.FromBase64String()
odpowiednio wewnątrz tych metod.
I umieść je bezpośrednio w klasie public abstract class Szyfrowanie
bo nie musisz mieć obiektu.
Wtedy oczywiście odpada potrzeba w klasach Szyfracja
i Deszyfracja
Użyj metody String.IsNullOrEmpty(String)
oraz if(Attachment?.Length>0)
dla typu byte[]
z tym że to akurat można śmiało wywalić ponieważ metody SzyfrowanieIO
i DeszyfrowanieIO
mogą nie przejmować parametrów Key
i IV
zaś brać ich bezpośrednio z pół statycznych.
Czyli powinno zostać coś w stylu:
public abstract class AesHelper
{
private static readonly byte[] IV = { 0x01, 0x01, 0x03, 0x04, 0x13, 0x06, 0x07, 0x08, 0x16, 0x10, 0x15, 0x12, 0x13, 0x14, 0x07, 0x15 };
private static readonly byte[] publicKey = { 0x01, 0x01, 0x03, 0x04, 0x13, 0x06, 0x07, 0x08, 0x16, 0x10, 0x15, 0x12, 0x13, 0x14, 0x07, 0x15 };
public static string Encrypt(string input)
{
if(String.NullOrEmpty(input)) throw new ArgumentNullException("input");
using(Aes aesAlg=Aes.Create())
{
aesAlg.Key=Key;
aesAlg.IV=IV;
ICryptoTransform encryptor=aesAlg.CreateEncryptor(Key,IV);
using(MemoryStream msEncrypt=new MemoryStream())
{
using(CryptoStream csEncrypt=new CryptoStream(msEncrypt,encryptor,CryptoStreamMode.Write))
{
using(StreamWriter swEncrypt=new StreamWriter(csEncrypt))
{
swEncrypt.Write(input);
return Convert.ToBase64String(msEncrypt.ToArray());
}
}
}
}
}
public static string Decrypt(string input)
{
if(String.NullOrEmpty(input)) throw new ArgumentNullException("input");
using(Aes aesAlg=Aes.Create())
{
aesAlg.Key=Key;
aesAlg.IV=IV;
ICryptoTransform decryptor=aesAlg.CreateDecryptor(Key,IV);
using(MemoryStream msDecrypt=new MemoryStream(Convert.FromBase64String(input)))
{
using(CryptoStream csDecrypt=new CryptoStream(msDecrypt,decryptor,CryptoStreamMode.Read))
{
using(StreamReader srDecrypt=new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}
}
}
Z tym że da się to skrócić do:
public abstract class AesHelper
{
private static readonly byte[] IV = { 0x01, 0x01, 0x03, 0x04, 0x13, 0x06, 0x07, 0x08, 0x16, 0x10, 0x15, 0x12, 0x13, 0x14, 0x07, 0x15 };
private static readonly byte[] publicKey = { 0x01, 0x01, 0x03, 0x04, 0x13, 0x06, 0x07, 0x08, 0x16, 0x10, 0x15, 0x12, 0x13, 0x14, 0x07, 0x15 };
private static string Aes CreateAes()
{
Aes aes=Aes.Create();
aes.Key=Key;
aes.IV=IV;
return aes;
}
public static string Decrypt(string input)
{
if(String.NullOrEmpty(input)) throw new ArgumentNullException("input");
return StreamReader srDecrypt=new StreamReader
(
new CryptoStream
(
new MemoryStream(Convert.FromBase64String(input)),
CreateAes().CreateDecryptor(Key,IV),
CryptoStreamMode.Read
)
)
.ReadToEnd();
}
public static string Encrypt(string input)
{
if(String.NullOrEmpty(input)) throw new ArgumentNullException("input");
using(MemoryStream msEncrypt=new MemoryStream())
{
new StreamWriter
(
new CryptoStream
(
msEncrypt,
CreateAes().CreateEncryptor(Key,IV),
CryptoStreamMode.Write
)
).Write(input);
return Convert.ToBase64String(msEncrypt.ToArray());
}
}
}
Uwaga pisano na kolanie.