Aku butuh beberapa string sederhana enkripsi, jadi saya menulis kode berikut (dengan "inspirasi" dari di sini):
// create and initialize a crypto algorithm
private static SymmetricAlgorithm getAlgorithm(string password) {
SymmetricAlgorithm algorithm = Rijndael.Create();
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
password, new byte[] {
0x53,0x6f,0x64,0x69,0x75,0x6d,0x20, // salty goodness
0x43,0x68,0x6c,0x6f,0x72,0x69,0x64,0x65
}
);
algorithm.Padding = PaddingMode.ISO10126;
algorithm.Key = rdb.GetBytes(32);
algorithm.IV = rdb.GetBytes(16);
return algorithm;
}
/*
* encryptString
* provides simple encryption of a string, with a given password
*/
public static string encryptString(string clearText, string password) {
SymmetricAlgorithm algorithm = getAlgorithm(password);
byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
return Convert.ToBase64String(ms.ToArray());
}
/*
* decryptString
* provides simple decryption of a string, with a given password
*/
public static string decryptString(string cipherText, string password) {
SymmetricAlgorithm algorithm = getAlgorithm(password);
byte[] cipherBytes = Convert.FromBase64String(cipherText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
return System.Text.Encoding.Unicode.GetString(ms.ToArray());
}
Kode muncul untuk bekerja dengan baik, kecuali bahwa ketika mendekripsi data dengan salah kunci, saya mendapatkan CryptographicException - "Padding adalah tidak valid dan tidak dapat dihapus" - pada cs.Close() baris di decryptString.
contoh kode:
string password1 = "password";
string password2 = "letmein";
string startClearText = "The quick brown fox jumps over the lazy dog";
string cipherText = encryptString(startClearText, password1);
string endClearText = decryptString(cipherText, password2); // exception thrown
Pertanyaan saya adalah, apakah ini yang diharapkan? Saya akan berpikir bahwa dekripsi dengan password yang salah hanya akan menghasilkan omong kosong output, bukan pengecualian.
Meskipun hal ini sudah dijawab saya pikir itu akan menjadi ide yang baik untuk menjelaskan mengapa itu yang diharapkan.
Padding sebuah skema ini biasanya diterapkan karena kebanyakan kriptografi filter tidak semantik aman dan untuk mencegah beberapa bentuk cryptoatacks. Misalnya, biasanya di RSA yang OAEP padding scheme digunakan yang mencegah beberapa macam serangan (seperti memilih plaintext attack atau membutakan).
Sebuah skema padding menambahkan beberapa (biasanya) sampah acak untuk pesan m sebelum pesan dikirim. Di OAEP metode, misalnya, dua Nubuat yang digunakan (ini adalah penjelasan sederhana):
Yang menyediakan anda dengan pengacakan untuk pesan dan dengan cara untuk menguji apakah pesan sampah atau tidak. Sebagai padding scheme adalah reversibel, bila anda mendekripsi pesan sedangkan anda dapat't mengatakan apa-apa tentang integritas dari pesan itu sendiri anda dapat, pada kenyataannya, membuat beberapa pernyataan tentang padding dan dengan demikian anda bisa tahu apakah pesan telah didekripsi dengan benar atau anda're melakukan sesuatu yang salah (saya.e seseorang telah dirusak dengan pesan atau anda're menggunakan kunci yang salah)
Saya mengalami yang sama "Padding adalah tidak valid dan tidak dapat dihapus." pengecualian, tapi dalam kasus saya kunci IV dan padding yang benar.
Ternyata bahwa pembilasan crypto stream semua itu hilang.
Seperti ini:
MemoryStream msr3 = new MemoryStream();
CryptoStream encStream = new CryptoStream(msr3, RijndaelAlg.CreateEncryptor(), CryptoStreamMode.Write);
encStream.Write(bar2, 0, bar2.Length);
// unless we flush the stream we would get "Padding is invalid and cannot be removed." exception when decoding
encStream.FlushFinalBlock();
byte[] bar3 = msr3.ToArray();
Jika anda ingin penggunaan yang benar, anda harus menambahkan otentikasi untuk anda ciphertext sehingga anda dapat memverifikasi bahwa itu adalah benar pasword atau bahwa ciphertext belum't telah dimodifikasi. Padding anda menggunakan ISO10126 hanya akan melempar pengecualian jika byte terakhir doesn't mendekripsi sebagai salah satu dari 16 nilai yang valid untuk padding (0x01-0x10). Jadi anda memiliki 1/16 kesempatan itu TIDAK melemparkan pengecualian dengan password yang salah, dimana jika anda mengotentikasi itu anda memiliki deterministik cara untuk mengetahui jika anda dekripsi adalah valid.
Menggunakan crypto api's sementara tampaknya mudah, sebenarnya agak mudah untuk membuat kesalahan. Misalnya anda menggunakan fixed garam untuk anda kunci dan iv derivasi, yang berarti setiap ciphertext yang dienkripsi dengan password yang sama akan menggunakan kembali's IV dengan kunci itu, yang memecah semantik keamanan dengan mode CBC, IV kebutuhan untuk menjadi tak terduga dan unik untuk kunci tertentu.
Untuk alasan itu mudah untuk membuat kesalahan, saya memiliki cuplikan kode, bahwa saya mencoba untuk terus ditinjau dan up to date (komentar, isu-isu selamat datang):
Contoh Modern Simetris Dikonfirmasi Enkripsi string C#.
Jika anda menggunakan it's AESThenHMAC.AesSimpleDecryptWithPassword(ciphertext, password)
ketika salah password yang digunakan, null
dikembalikan, jika ciphertext atau iv telah dimodifikasi posting enkripsi null
kembali, anda tidak akan pernah mendapatkan data sampah kembali, atau padding terkecuali.
Jika anda've dikesampingkan kunci-ketidakcocokan, maka selain FlushFinalBlock()
(lihat Yani's jawaban), menyebut Close()
pada CryptoStream
juga akan cukup.
Jika anda membersihkan sumber daya secara ketat dengan menggunakan
blok, pastikan untuk sarang blok untuk CryptoStream
itu sendiri:
using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
{
using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
{
encStream.Write(bar2, 0, bar2.Length);
} // implicit close
byte[] encArray = ms.ToArray();
}
I've telah digigit oleh ini (atau yang mirip):
using (MemoryStream ms = new MemoryStream())
using (var enc = RijndaelAlg.CreateEncryptor())
using (CryptoStream encStream = new CryptoStream(ms, enc, CryptoStreamMode.Write))
{
encStream.Write(bar2, 0, bar2.Length);
byte[] encArray = ms.ToArray();
} // implicit close -- too late!
Alasan lain dari pengecualian mungkin kondisi balapan antara beberapa thread dekripsi menggunakan logika - asli implementasi ICryptoTransform tidak thread-safe (misalnya SymmetricAlgorithm), sehingga harus dimasukkan ke eksklusif bagian, misalnya menggunakan kunci. Silakan lihat di sini untuk lebih jelasnya: http://www.make-awesome.com/2011/07/system-security-cryptography-and-thread-safety/