AES-Dateiverschlüsselung_Fehler mit Videos?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    AES-Dateiverschlüsselung_Fehler mit Videos?

    Hallo Leute, habe bei meinem kleinen Programm zur AES-Dateiverschlüsselung irgendwie Probleme beim Entschlüsseln von Videos...
    Der VLC-Media-Player sagt, dass die Datei beschädigt ist :S

    Andere Dateiformate (z.B. .txt,.jpg,...) funktionieren ohne Probleme, hat irgendwer da vielleicht ne Idee?
    Vielen Dank schon mal ;)

    Kleiner Hinweis, wie das Programm funktioniert:
    -Passworteingabe über Textbox
    -Salteingabe über Textbox
    -Dateiauswahl (Eingabedatei) über OpenFileDialog
    -Dateiauswahl (Ausgabedatei) über SaveFileDialog
    --> Der Clou: Die Ausgabedatei kann jedes beliebige Dateiformat haben, zum Entschlüsseln muss man sich nur an das ursprüngliche Format,
    den Salt und das Passwort erinnern 8-)

    Bild der Software:



    Das Projekt:

    AES-FileCryptor.rar

    Code:
    Spoiler anzeigen

    Quellcode

    1. Imports System.Security.Cryptography
    2. Imports System.IO
    3. Imports System.Text
    4. Public Class Main
    5. Dim Salt() As Byte 'Saltwert erzeugen
    6. Dim Sprache As String 'Sprache erzeugen
    7. Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    8. Call Button_Alle_Resetten_Click(sender, e) 'Alles resetten
    9. GC.Collect() 'Garbage-Collector aufrufen
    10. Blocksize = 1048576 'Blocksize auf 1 MB setzen
    11. 'Datei öffnen und Sprache auslesen:
    12. Try
    13. 'Datei öffnen
    14. Dim fs As FileStream = New FileStream(System.AppDomain.CurrentDomain.BaseDirectory() & "Config.ini", FileMode.OpenOrCreate, FileAccess.ReadWrite)
    15. 'Stream öffnen
    16. Dim r As StreamReader = New StreamReader(fs)
    17. 'Zeiger auf den Anfang
    18. r.BaseStream.Seek(0, SeekOrigin.Begin)
    19. 'Alle Zeilen lesen und an Console ausgeben
    20. While r.Peek() > -1
    21. Sprache = r.ReadLine() 'Sprache festsetzen
    22. End While
    23. 'Reader und Stream schließen
    24. r.Close()
    25. fs.Close()
    26. Catch ex As Exception
    27. MessageBox.Show(ex.ToString) 'Fehlermeldung ausgeben
    28. End Try
    29. 'Verschlüsselungsarten anzeigen:
    30. ComboBox_Art.Items.Add("AES-256") 'AES-256 als Verschlüsselungsart hinzufügen
    31. ComboBox_Art.Items.Add("AES-128") 'AES-128 als Verschlüsselungsart hinzufügen
    32. ComboBox_Art.SelectedIndex = 0 'Vorauswahl setzen, dass Combobox nicht leer
    33. 'Default-Saltwert verwenden setzen:
    34. CheckBox_DefaultSalt.Checked = True 'Default-Saltwert verwenden auf wahr setzen
    35. 'Sprache anpassen:
    36. Select Case Sprache
    37. Case "DE"
    38. RadioButton_Deutsch.Checked = True 'RadioButton_Deutsch auswählen
    39. Case Else
    40. RadioButton_Englisch.Checked = True 'RadioButton_Englisch auswählen
    41. End Select
    42. End Sub
    43. Private Sub EncryptFile(ByVal File As String) 'Eingangsdatei als Byte-Array einlesen
    44. GC.Collect() 'Garbage-Collector aufrufen
    45. BytesBereitsGelesen = 0 'BytesBereitsGelesen zurücksetzen
    46. Dim fInfo As New FileInfo(File) 'FileInfo anlegen
    47. Dim numBytes As Long = fInfo.Length 'Bytezahl auslesen
    48. Dim InStream As New FileStream(File, FileMode.Open, FileAccess.Read) 'FileStream (für Input) öffnen
    49. Dim br As New BinaryReader(InStream) 'Reader öffnen
    50. Dim data As Byte() 'Datenarray anlegen
    51. Dim OutStream As FileStream = New FileStream(Ausgabedateipfad, FileMode.Create) 'FileStream (für Output) öffnen
    52. ProgressBar_Verschluesseln.Maximum = numBytes / Blocksize 'Verhältnis ausrechnen
    53. If ProgressBar_Verschluesseln.Maximum = 0 Then
    54. ProgressBar_Verschluesseln.Maximum = 1
    55. End If
    56. 'While numBytes Mod Blocksize = 0
    57. 'Blocksize = Blocksize - 1 'Wenn genaue Dateigröße auf die Grenze fällt --> Kein cs.FlushFinalBlock --> Fehler
    58. 'End While
    59. While BytesBereitsGelesen < numBytes
    60. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    61. If (numBytes - BytesBereitsGelesen) > Blocksize Then
    62. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    63. data = br.ReadBytes(Blocksize) 'Genau Blocksize lesen
    64. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    65. BytesBereitsGelesen = BytesBereitsGelesen + Blocksize 'BytesBereitsGelesen um Blocksize erhöhen
    66. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    67. Call EncryptAES(AESSize, data, RichTextBox_Passwort.Text, False) 'Verschlüsselung aufrufen
    68. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    69. OutStream.Write(EncryptedString_, 0, EncryptedString_.Length) 'Daten schreiben
    70. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    71. ProgressBar_Verschluesseln.PerformStep() 'Next step
    72. Else
    73. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    74. data = br.ReadBytes(numBytes - BytesBereitsGelesen) 'Genau Blocksize lesen
    75. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    76. BytesBereitsGelesen = numBytes 'BytesBereitsGelesen um Blocksize erhöhen
    77. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    78. Call EncryptAES(AESSize, data, RichTextBox_Passwort.Text, True) 'Verschlüsselung aufrufen
    79. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    80. OutStream.Write(EncryptedString_, 0, EncryptedString_.Length) 'Daten schreiben
    81. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    82. ProgressBar_Verschluesseln.PerformStep() 'Next step
    83. End If
    84. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    85. End While
    86. OutStream.Close() 'FileStream (für Output) schließen
    87. InStream.Close() 'FileStream (für Input) schließen
    88. br.Close() 'Reader schließen
    89. Select Case Sprache
    90. Case "DE"
    91. MessageBox.Show("Datei " & Eingabedateipfad & " erfolgreich verschlüsselt!", "Datei erfolgreich verschlüsselt!", MessageBoxButtons.OK, MessageBoxIcon.Information) 'Meldung ausgeben
    92. Case Else
    93. MessageBox.Show("File " & Eingabedateipfad & " successfully encrypted!", "File successfully encrypted!", MessageBoxButtons.OK, MessageBoxIcon.Information) 'Meldung ausgeben
    94. End Select
    95. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    96. End Sub
    97. Private Sub DecryptFile(ByVal File As String) 'Eingangsdatei als Byte-Array einlesen
    98. GC.Collect() 'Garbage-Collector aufrufen
    99. BytesBereitsGelesen = 0 'BytesBereitsGelesen zurücksetzen
    100. Dim fInfo As New FileInfo(File) 'FileInfo anlegen
    101. Dim numBytes As Long = fInfo.Length 'Bytezahl auslesen
    102. Dim InStream As New FileStream(File, FileMode.Open, FileAccess.Read) 'FileStream (für Input) öffnen
    103. Dim br As New BinaryReader(InStream) 'Reader öffnen
    104. Dim data As Byte() 'Datenarray anlegen
    105. Dim OutStream As FileStream = New FileStream(Ausgabedateipfad, FileMode.Create) 'FileStream (für Output) öffnen
    106. ProgressBar_Verschluesseln.Maximum = numBytes / Blocksize 'Verhältnis ausrechnen
    107. If ProgressBar_Verschluesseln.Maximum = 0 Then
    108. ProgressBar_Verschluesseln.Maximum = 1
    109. End If
    110. 'While numBytes Mod Blocksize = 0
    111. 'Blocksize = Blocksize - 1 'Wenn genaue Dateigröße auf die Grenze fällt --> Kein cs.FlushFinalBlock --> Fehler
    112. 'End While
    113. While BytesBereitsGelesen < numBytes
    114. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    115. If (numBytes - BytesBereitsGelesen) > Blocksize Then
    116. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    117. data = br.ReadBytes(Blocksize) 'Genau Blocksize lesen
    118. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    119. BytesBereitsGelesen = BytesBereitsGelesen + Blocksize 'BytesBereitsGelesen um Blocksize erhöhen
    120. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    121. Call DecryptAES(AESSize, data, RichTextBox_Passwort.Text, False) 'Verschlüsselung aufrufen
    122. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    123. OutStream.Write(DecryptedString_, 0, DecryptedString_.Length) 'Daten schreiben
    124. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    125. ProgressBar_Verschluesseln.PerformStep() 'Next step
    126. Else
    127. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    128. data = br.ReadBytes(numBytes - BytesBereitsGelesen) 'Genau Blocksize lesen
    129. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    130. BytesBereitsGelesen = numBytes 'BytesBereitsGelesen um Blocksize erhöhen
    131. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    132. Call DecryptAES(AESSize, data, RichTextBox_Passwort.Text, True) 'Verschlüsselung aufrufen
    133. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    134. OutStream.Write(DecryptedString_, 0, DecryptedString_.Length) 'Daten schreiben
    135. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    136. ProgressBar_Verschluesseln.PerformStep() 'Next step
    137. End If
    138. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    139. End While
    140. OutStream.Close() 'FileStream (für Output) schließen
    141. InStream.Close() 'FileStream (für Input) schließen
    142. br.Close() 'Reader schließen
    143. Select Case Sprache
    144. Case "DE"
    145. MessageBox.Show("Datei " & Eingabedateipfad & " erfolgreich entschlüsselt!", "Datei erfolgreich entschlüsselt!", MessageBoxButtons.OK, MessageBoxIcon.Information) 'Meldung ausgeben
    146. Case Else
    147. MessageBox.Show("File " & Eingabedateipfad & " successfully decrypted!", "File successfully decrypted!", MessageBoxButtons.OK, MessageBoxIcon.Information) 'Meldung ausgeben
    148. End Select
    149. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    150. End Sub
    151. Private Sub RadioButton_Deutsch_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton_Deutsch.CheckedChanged
    152. If RadioButton_Deutsch.Checked = True Then
    153. Call AllesAufDeutsch() 'Alles auf Deutsch übersetzen
    154. Else
    155. Call AllesAufEnglisch() 'Alles auf Englisch übersetzen
    156. End If
    157. End Sub
    158. Private Sub RadioButton_Englisch_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton_Englisch.CheckedChanged
    159. If RadioButton_Englisch.Checked = True Then
    160. Call AllesAufEnglisch() 'Alles auf Englisch übersetzen
    161. Else
    162. Call AllesAufDeutsch() 'Alles auf Deutsch übersetzen
    163. End If
    164. End Sub
    165. Private Sub AllesAufDeutsch() 'Alles auf Deutsch übersetzen
    166. Me.Text = "AES Dateiverschlüsselung" 'Text von Form setzen
    167. Label_Art.Text = "Bitte Verschlüsselungsart auswählen:" 'Label_Art Text setzen
    168. Label_Salt.Text = "Salteingabe:" 'Label_Salt Text setzen
    169. Label_Passwort.Text = "Passworteingabe:" 'Label_Passwort Text setzen
    170. Label_Eingabe.Text = "Dateieingabe:" 'Label_Eingabe Text setzen
    171. Label_Ausgabe.Text = "Dateiausgabe:" 'Label_Ausgabe Text setzen
    172. Button_Verschluesseln.Text = "Verschlüsseln" 'Button_Verschluesseln Text setzen
    173. Button_Entschluesseln.Text = "Entschlüsseln" 'Button_Entschluesseln Text setzen
    174. Button_Alle_Resetten.Text = "Alles löschen" 'Button_Alle_Resetten Text setzen
    175. CheckBox_DefaultSalt.Text = "Default Salt-Wert benutzen" 'CheckBox_DefaultSalt Text setzen
    176. Label_Sprache.Text = "Sprache auswählen:" 'Label_Sprache Text setzen
    177. RadioButton_Deutsch.Text = "Deutsch" 'RadioButton_Deutsch Text setzen
    178. RadioButton_Englisch.Text = "Englisch" 'RadioButton_Englisch Text setzen
    179. Sprache = "DE" 'Sprache festlegen
    180. OpenFileDialog_Eingabe.Filter = "Alle Dateien (*.*)|*.*" 'OpenFileDialog_Eingabe Filter setzen
    181. OpenFileDialog_Eingabe.Title = "Eingabedatei auswählen" 'OpenFileDialog_Eingabe Titel setzen
    182. SaveFileDialog_Ausgabe.Filter = "Alle Dateien (*.*)|*.*" 'SaveFileDialog_Ausgabe Filter setzen
    183. SaveFileDialog_Ausgabe.Title = "Ausgabedatei auswählen" 'SaveFileDialog_Ausgabe Titel setzen
    184. Button_Eingabe.Text = "Eingabedatei auswählen" 'Button_Eingabe Text setzen
    185. Button_Ausgabe.Text = "Ausgabedatei auswählen" 'Button_Ausgabe Text setzen
    186. Label_Ausgabe.Text = "Dateiausgabe: " 'Label_Ausgabe Text setzen
    187. End Sub
    188. Private Sub AllesAufEnglisch() 'Alles auf Englisch übersetzen
    189. Me.Text = "AES File Cryptor" 'Text von Form setzen
    190. Label_Art.Text = "Choose encryption method:" 'Label_Art Text setzen
    191. Label_Salt.Text = "Salt input:" 'Label_Salt Text setzen
    192. Label_Passwort.Text = "Password input:" 'Label_Passwort Text setzen
    193. Label_Eingabe.Text = "File input:" 'Label_Eingabe Text setzen
    194. Label_Ausgabe.Text = "File output:" 'Label_Ausgabe Text setzen
    195. Button_Verschluesseln.Text = "Encrypt" 'Button_Verschluesseln Text setzen
    196. Button_Entschluesseln.Text = "Decrypt" 'Button_Entschluesseln Text setzen
    197. Button_Alle_Resetten.Text = "Clear all" 'Button_Alle_Resetten Text setzen
    198. CheckBox_DefaultSalt.Text = "Use default Salt value" 'CheckBox_DefaultSalt Text setzen
    199. Label_Sprache.Text = "Choose language:" 'Label_Sprache Text setzen
    200. RadioButton_Deutsch.Text = "German" 'RadioButton_Deutsch Text setzen
    201. RadioButton_Englisch.Text = "English" 'RadioButton_Englisch Text setzen
    202. Sprache = "EN" 'Sprache festlegen
    203. OpenFileDialog_Eingabe.Filter = "All files (*.*)|*.*" 'OpenFileDialog_Eingabe Filter setzen
    204. OpenFileDialog_Eingabe.Title = "Select input file" 'OpenFileDialog_Eingabe Titel setzen
    205. SaveFileDialog_Ausgabe.Filter = "All files (*.*)|*.*" 'SaveFileDialog_Ausgabe Filter setzen
    206. SaveFileDialog_Ausgabe.Title = "Select output file" 'SaveFileDialog_Ausgabe Titel setzen
    207. Button_Eingabe.Text = "Select input file" 'Button_Eingabe Text setzen
    208. Button_Ausgabe.Text = "Select output file" 'Button_Ausgabe Text setzen
    209. Label_Ausgabe.Text = "File output:" 'Label_Ausgabe Text setzen
    210. End Sub
    211. Private Sub CheckBox_DefaultSalt_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox_DefaultSalt.CheckedChanged 'DefaultSaltCheck
    212. Select Case CheckBox_DefaultSalt.Checked
    213. Case True
    214. RichTextBox_Salt.Enabled = False 'Salteingabe sperren
    215. Case False
    216. RichTextBox_Salt.Enabled = True 'Salteingabe entsperren
    217. End Select
    218. End Sub
    219. Private Sub Button_Verschluesseln_Click(sender As Object, e As EventArgs) Handles Button_Verschluesseln.Click 'Text verschlüsseln
    220. Try
    221. LastBlockFlushed = False 'LastBlockFlushed auf false setzen
    222. ProgressBar_Verschluesseln.Value = 0 'ProgressBar_Verschluesseln zurücksetzen
    223. Select Case ComboBox_Art.SelectedIndex
    224. Case 0 'AES-256 ausgewählt
    225. AESSize = 256 'AESSize auf 256 setzen
    226. If RichTextBox_Passwort.Text = "" Or Label_Eingabedatei.Text = "" Then 'Wenn Felder leer sind
    227. Select Case Sprache
    228. Case "DE"
    229. MessageBox.Show("Passwort oder Dateieingabe ist leer") 'Fehlermeldung ausgeben
    230. Case Else
    231. MessageBox.Show("Password or file input is empty") 'Fehlermeldung ausgeben
    232. End Select
    233. Else 'Wenn Felder gefüllt sind
    234. If CheckBox_DefaultSalt.Checked = True Then 'Default-Saltwert verwenden
    235. Salt = System.Text.Encoding.UTF8.GetBytes("Test")
    236. Call EncryptFile(Label_Eingabedatei.Text) 'Datei verschlüsseln
    237. Else 'Benutzerdefinierten Saltwert verwenden
    238. If RichTextBox_Salt.TextLength < 8 Then 'Wenn Saltwert zu klein ist
    239. Select Case Sprache
    240. Case "DE"
    241. MessageBox.Show("Saltwert muss mindestens 8 Zeichen enthalten") 'Fehlermeldung ausgeben
    242. Case Else
    243. MessageBox.Show("Salt value must contain at least 8 characters") 'Fehlermeldung ausgeben
    244. End Select
    245. Else
    246. Salt = System.Text.Encoding.UTF8.GetBytes(RichTextBox_Salt.Text) 'Salt aus Benutzereingabe auslesen
    247. Call EncryptFile(Label_Eingabedatei.Text) 'Datei verschlüsseln
    248. End If
    249. End If
    250. End If
    251. Case 1 'AES-128 ausgewählt
    252. AESSize = 128 'AESSize auf 128 setzen
    253. If RichTextBox_Passwort.Text = "" Or Label_Eingabedatei.Text = "" Then 'Wenn Felder leer sind
    254. Select Case Sprache
    255. Case "DE"
    256. MessageBox.Show("Passwort oder Dateieingabe ist leer") 'Fehlermeldung ausgeben
    257. Case Else
    258. MessageBox.Show("Password or file input is empty") 'Fehlermeldung ausgeben
    259. End Select
    260. Else 'Wenn Felder gefüllt sind
    261. If CheckBox_DefaultSalt.Checked = True Then 'Default-Saltwert verwenden
    262. Salt = System.Text.Encoding.UTF8.GetBytes("Test")
    263. Call EncryptFile(Label_Eingabedatei.Text) 'Datei verschlüsseln
    264. Else 'Benutzerdefinierten Saltwert verwenden
    265. If RichTextBox_Salt.TextLength < 8 Then 'Wenn Saltwert zu klein ist
    266. Select Case Sprache
    267. Case "DE"
    268. MessageBox.Show("Saltwert muss mindestens 8 Zeichen enthalten") 'Fehlermeldung ausgeben
    269. Case Else
    270. MessageBox.Show("Salt value must contain at least 8 characters") 'Fehlermeldung ausgeben
    271. End Select
    272. Else
    273. Salt = System.Text.Encoding.UTF8.GetBytes(RichTextBox_Salt.Text) 'Salt aus Benutzereingabe auslesen
    274. Call EncryptFile(Label_Eingabedatei.Text) 'Datei verschlüsseln
    275. End If
    276. End If
    277. End If
    278. End Select
    279. Catch ex As Exception
    280. MessageBox.Show(ex.ToString) 'Fehlermeldung ausgeben
    281. End Try
    282. End Sub
    283. Private Sub Button_Entschluesseln_Click(sender As Object, e As EventArgs) Handles Button_Entschluesseln.Click
    284. Try
    285. LastBlockFlushed = False 'LastBlockFlushed auf false setzen
    286. ProgressBar_Verschluesseln.Value = 0 'ProgressBar_Verschluesseln zurücksetzen
    287. Select Case ComboBox_Art.SelectedIndex
    288. Case 0 'AES-256 ausgewählt
    289. AESSize = 256 'AESSize auf 256 setzen
    290. If RichTextBox_Passwort.Text = "" Or Label_Eingabedatei.Text = "" Then 'Wenn Felder leer sind
    291. Select Case Sprache
    292. Case "DE"
    293. MessageBox.Show("Passwort oder Dateieingabe ist leer") 'Fehlermeldung ausgeben
    294. Case Else
    295. MessageBox.Show("Password or file input is empty") 'Fehlermeldung ausgeben
    296. End Select
    297. Else 'Wenn Felder gefüllt sind
    298. If CheckBox_DefaultSalt.Checked = True Then 'Default-Saltwert verwenden
    299. Salt = System.Text.Encoding.UTF8.GetBytes("Test")
    300. Call DecryptFile(Label_Eingabedatei.Text) 'Datei entschlüsseln
    301. Else 'Benutzerdefinierten Saltwert verwenden
    302. If RichTextBox_Salt.TextLength < 8 Then 'Wenn Saltwert zu klein ist
    303. Select Case Sprache
    304. Case "DE"
    305. MessageBox.Show("Saltwert muss mindestens 8 Zeichen enthalten") 'Fehlermeldung ausgeben
    306. Case Else
    307. MessageBox.Show("Salt value must contain at least 8 characters") 'Fehlermeldung ausgeben
    308. End Select
    309. Else
    310. Salt = System.Text.Encoding.UTF8.GetBytes(RichTextBox_Salt.Text) 'Salt aus Benutzereingabe auslesen
    311. Call DecryptFile(Label_Eingabedatei.Text) 'Datei entschlüsseln
    312. End If
    313. End If
    314. End If
    315. Case 1 'AES-128 ausgewählt
    316. AESSize = 128 'AESSize auf 128 setzen
    317. If RichTextBox_Passwort.Text = "" Or Label_Eingabedatei.Text = "" Then 'Wenn Felder leer sind
    318. Select Case Sprache
    319. Case "DE"
    320. MessageBox.Show("Passwort oder Dateieingabe ist leer") 'Fehlermeldung ausgeben
    321. Case Else
    322. MessageBox.Show("Password or file input is empty") 'Fehlermeldung ausgeben
    323. End Select
    324. Else 'Wenn Felder gefüllt sind
    325. If CheckBox_DefaultSalt.Checked = True Then 'Default-Saltwert verwenden
    326. Salt = System.Text.Encoding.UTF8.GetBytes("Test")
    327. Call DecryptFile(Label_Eingabedatei.Text) 'Datei entschlüsseln
    328. Else 'Benutzerdefinierten Saltwert verwenden
    329. If RichTextBox_Salt.TextLength < 8 Then 'Wenn Saltwert zu klein ist
    330. Select Case Sprache
    331. Case "DE"
    332. MessageBox.Show("Saltwert muss mindestens 8 Zeichen enthalten") 'Fehlermeldung ausgeben
    333. Case Else
    334. MessageBox.Show("Salt value must contain at least 8 characters") 'Fehlermeldung ausgeben
    335. End Select
    336. Else
    337. Salt = System.Text.Encoding.UTF8.GetBytes(RichTextBox_Salt.Text) 'Salt aus Benutzereingabe auslesen
    338. Call DecryptFile(Label_Eingabedatei.Text) 'Datei entschlüsseln
    339. End If
    340. End If
    341. End If
    342. End Select
    343. Catch ex As Exception
    344. MessageBox.Show(ex.ToString) 'Fehlermeldung ausgeben
    345. End Try
    346. End Sub
    347. Private Sub Button_Alle_Resetten_Click(sender As Object, e As EventArgs) Handles Button_Alle_Resetten.Click
    348. RichTextBox_Salt.Clear() 'RichTextBox_Salt leeren
    349. RichTextBox_Passwort.Clear() 'RichTextBox_Passwort leeren
    350. Label_Eingabedatei.Text = "" 'Label_Eingabedatei leeren
    351. Label_Ausgabedatei.Text = "" 'Label_Ausgabedatei leeren
    352. ProgressBar_Verschluesseln.Value = 0 'ProgressBar_Verschluesseln resetten
    353. End Sub
    354. 'AES
    355. #Region "Zustandsvariablen"
    356. Private EncryptedString_() As Byte
    357. Private DecryptedString_() As Byte
    358. #End Region
    359. #Region "Methoden"
    360. ' Verschlüsseln
    361. Public Sub EncryptAES(ByVal AESKeySize As Int32, ByVal DecryptedString() As Byte, ByVal Password As String, ByVal IsLastBlock As Boolean)
    362. Dim GenerierterKey As New Rfc2898DeriveBytes(Password, Salt)
    363. Dim AES As New AesManaged
    364. AES.KeySize = AESKeySize ' möglich sind 128 oder 256 bit
    365. AES.BlockSize = 128
    366. ' Algorithmus initialisieren:
    367. AES.Key = GenerierterKey.GetBytes(AES.KeySize \ 8)
    368. AES.IV = GenerierterKey.GetBytes(AES.BlockSize \ 8)
    369. ' Memory-Stream und Crypto-Stream erzeugen -> CreateEncryptor()
    370. Dim ms As New IO.MemoryStream
    371. Dim cs As New CryptoStream(ms, AES.CreateEncryptor(), _
    372. CryptoStreamMode.Write)
    373. ' Daten verschlüsseln:
    374. Dim Data() As Byte
    375. Data = DecryptedString
    376. cs.Write(Data, 0, Data.Length)
    377. If IsLastBlock = True Then
    378. cs.FlushFinalBlock()
    379. cs.Close()
    380. LastBlockFlushed = True
    381. End If
    382. ' Verschlüsselte Daten als Byte ausgeben:
    383. EncryptedString_ = ms.ToArray
    384. ms.Close()
    385. AES.Clear()
    386. End Sub
    387. ' Entschlüsseln
    388. Public Sub DecryptAES(ByVal AESKeySize As Int32, ByVal EncryptedString() As Byte, ByVal Password As String, ByVal IsLastBlock As Boolean)
    389. Dim GenerierterKey As New Rfc2898DeriveBytes(Password, Salt)
    390. ' Instanzierung des AES-Algorithmus-Objekts:
    391. Dim AES As New AesManaged
    392. ' Ein mit 256 bit verschlüsseltes Byte kann
    393. ' auch nur mit 256 bit entschlüsselt werden!
    394. AES.KeySize = AESKeySize ' möglich sind 128 oder 256 bit
    395. AES.BlockSize = 128
    396. ' Algorithmus initialisieren:
    397. AES.Key = GenerierterKey.GetBytes(AES.KeySize \ 8)
    398. AES.IV = GenerierterKey.GetBytes(AES.BlockSize \ 8)
    399. ' Memory-Stream und Crypto-Stream erzeugen -> CreateDecryptor()
    400. Dim ms As New IO.MemoryStream
    401. Dim cs As New CryptoStream(ms, AES.CreateDecryptor(), _
    402. CryptoStreamMode.Write)
    403. Try ' Daten entschlüsseln:
    404. Dim Data() As Byte
    405. Data = EncryptedString
    406. cs.Write(Data, 0, Data.Length)
    407. If IsLastBlock = True Then
    408. cs.FlushFinalBlock()
    409. cs.Close()
    410. LastBlockFlushed = True
    411. End If
    412. ' Die entschlüsselten Daten als Byte ausgeben:
    413. DecryptedString_ = ms.ToArray
    414. ms.Close()
    415. AES.Clear()
    416. Catch ex As Exception
    417. MessageBox.Show(ex.ToString)
    418. End Try
    419. End Sub
    420. #End Region
    421. #Region "Eigenschaften"
    422. ReadOnly Property EncryptedString() As Byte()
    423. Get
    424. Return EncryptedString_
    425. End Get
    426. End Property
    427. ReadOnly Property DecryptedString() As Byte()
    428. Get
    429. Return DecryptedString_
    430. End Get
    431. End Property
    432. #End Region
    433. 'AES
    434. Private Sub Button_Eingabe_Click(sender As Object, e As EventArgs) Handles Button_Eingabe.Click
    435. If OpenFileDialog_Eingabe.ShowDialog() = DialogResult.OK Then
    436. Eingabedateipfad = OpenFileDialog_Eingabe.FileName 'Eingabedateipfad speichern
    437. Label_Eingabedatei.Text = Eingabedateipfad 'Label_Eingabedatei Text ausgeben
    438. Select Case Sprache
    439. Case "DE"
    440. Label_Ausgabe.Text = "Dateiausgabe: " 'Label_Ausgabe Text setzen
    441. Case Else
    442. Label_Ausgabe.Text = "File output:" 'Label_Ausgabe Text setzen
    443. End Select
    444. End If
    445. End Sub
    446. Private Sub Button_Ausgabe_Click(sender As Object, e As EventArgs) Handles Button_Ausgabe.Click
    447. If SaveFileDialog_Ausgabe.ShowDialog() = DialogResult.OK Then
    448. Ausgabedateipfad = SaveFileDialog_Ausgabe.FileName 'Ausgabedateipfad speichern
    449. Label_Ausgabedatei.Text = Ausgabedateipfad 'Label_Ausgabedatei Text ausgeben
    450. Select Case Sprache
    451. Case "DE"
    452. Label_Ausgabe.Text = "Dateiausgabe: " 'Label_Ausgabe Text setzen
    453. Case Else
    454. Label_Ausgabe.Text = "File output:" 'Label_Ausgabe Text setzen
    455. End Select
    456. End If
    457. End Sub
    458. End Class


    Expander eingefügt. ~Thunderbolt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Thunderbolt“ ()

    Ich habe den Code nur ganz grob überflogen, denn ich blicke da nicht wirklich durch.
    Gleich präventiv ein paar Links zum Durchlesen:
    Option Strict On: home.arcor.de/eckardahlers/Pro…/Blogs/WarumStrictOn.html
    VB6-Kompatibilitäts-Funktionen: vb-paradise.de/allgemeines/tip…euen-vb-net-alternativen/
    Und woher kommt eigentlich das Call? Methoden können auch ohne das aufgerufen werden.

    Wie symmetrische Verschlüsselungen prinzipiell funktionieren hab ich hier schon mal erklärt.
    Mir kommt es komisch vor, dass der User den Salt selbst eingeben muss. Das macht keinen Sinn, denn der sollte nicht nur auf Bytes beschränkt sein, die durch druckbare Zeichen repräsentiert werden können. Im Gegenteil. Der Salt muss durch einen kryptographisch starken Zufallszahlengenerator erstellt werden. Und beim Entschlüsseln muss der User den auch nicht eingeben, denn der darf gerne im "Klartext" der verschlüsselten Datei beiliegen. Typischerweise schreibt man den an den Anfang der Verschlüsselten Datei.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ok, Option Strict On ist drinnen.
    Und woher kommt eigentlich das Call? Methoden können auch ohne das aufgerufen werden.

    Gut zu wissen... Kommt daher, dass ich zuvor mal in VB6 gearbeitet habe...

    Mir kommt es komisch vor, dass der User den Salt selbst eingeben muss. Das macht keinen Sinn, denn der sollte nicht nur auf Bytes beschränkt sein, die durch druckbare Zeichen repräsentiert werden können. Im Gegenteil. Der Salt muss durch einen kryptographisch starken Zufallszahlengenerator erstellt werden. Und beim Entschlüsseln muss der User den auch nicht eingeben, denn der darf gerne im "Klartext" der verschlüsselten Datei beiliegen. Typischerweise schreibt man den an den Anfang der Verschlüsselten Datei.


    Das Ziel ist eben, dass man sozusagen 2 "Passwörter" hat, also Salt und Passwort.
    Es funktioniert ja auch soweit, nur mit Videos irgendwie nicht...
    Als erstes würde ich dich bitten die Vbnet-Codetags zu nutzen, so kann man sich das kaum antun.
    Was mir so beim überfliegen aufgefallen ist, dass du das ganze im Hauptthread ausführst und die Form dann zu Events zwingst. Ich würde das ganze in Nebenthreads packen. Desweiteren würde ich nicht alles aufeinmal in den Ram laden. Nen Filestream erstellen, in ein Byte-Array(mit 1024 als Grenze) laden, dieses verschlüsseln, den Buffer dann entweder direkt schreiben oder vllt auch an nen zweiten Thread schicken zum schreiben, dann den Buffer neufüllen und das ganze nochmal.

    LG
    Es funktioniert ja

    Na anscheinend nicht. Für Verschlüsselungen macht es keinen Unterschied, was die Bytes darstellen. Entweder es funktioniert, oder es funktioniert nicht.
    Kannst Du mal eine Beispiel-Datei hochladen? Also unverschlüsselt vorher, verschlüsselt und entschlüsselt nachher. Dazu das verwendete Passwort und den Salt, den Du angegeben hast (in einer geeigneten Darstellung, siehe unten). Kannst Du auch beschreiben, wie Du Passwort und Salt in Key und IV umwandelst?
    Wie bereits gesagt soll der Salt nicht vom User eingegeben werden, sondern von einem kryptographisch starken Zufalsszahlengenerator (RNGCryptoServiceProvider) erstellt werden. Und der kümmert sich halt nicht darum, dass die Bytes zwischen 65 und 96 oder so sind (A bzs Z), sondern der nimmt den ganzen Wertebereich von Bytes. Macht ja sonst auch keinen Sinn.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Als erstes würde ich dich bitten die Vbnet-Codetags zu nutzen, so kann man sich das kaum antun.

    Du wirst lachen, aber das hab ich getan, keine Ahnung, warum es nicht so angezeigt wird ?(
    Was mir so beim überfliegen aufgefallen ist, dass du das ganze im
    Hauptthread ausführst und die Form dann zu Events zwingst. Ich würde das
    ganze in Nebenthreads packen.

    Mit Threading in VB kenn ich mich leider 0,0 aus
    Desweiteren würde ich nicht alles aufeinmal in den Ram laden. Nen
    Filestream erstellen, in ein Byte-Array(mit 1024 als Grenze) laden,
    dieses verschlüsseln, den Buffer dann entweder direkt schreiben oder
    vllt auch an nen zweiten Thread schicken zum schreiben, dann den Buffer
    neufüllen und das ganze nochmal.

    Mach ich doch:

    VB.NET-Quellcode

    1. While BytesBereitsGelesen < numBytes
    2. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    3. If (numBytes - BytesBereitsGelesen) > Blocksize Then
    4. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    5. data = br.ReadBytes(Blocksize) 'Genau Blocksize lesen
    6. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    7. BytesBereitsGelesen = BytesBereitsGelesen + Blocksize 'BytesBereitsGelesen um Blocksize erhöhen
    8. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    9. Call EncryptAES(AESSize, data, RichTextBox_Passwort.Text, False) 'Verschlüsselung aufrufen
    10. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    11. OutStream.Write(EncryptedString_, 0, EncryptedString_.Length) 'Daten schreiben
    12. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    13. ProgressBar_Verschluesseln.PerformStep() 'Next step
    14. Else
    15. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    16. data = br.ReadBytes(numBytes - BytesBereitsGelesen) 'Genau Blocksize lesen
    17. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    18. BytesBereitsGelesen = numBytes 'BytesBereitsGelesen um Blocksize erhöhen
    19. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    20. Call EncryptAES(AESSize, data, RichTextBox_Passwort.Text, True) 'Verschlüsselung aufrufen
    21. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    22. OutStream.Write(EncryptedString_, 0, EncryptedString_.Length) 'Daten schreiben
    23. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    24. ProgressBar_Verschluesseln.PerformStep() 'Next step
    25. End If
    26. System.Windows.Forms.Application.DoEvents() 'Dass Form nicht einfriert
    27. End While


    Na anscheinend nicht.

    Für alle getesteten Dateien außer Videos...
    Kannst
    Du mal eine Beispiel-Datei hochladen? Also unverschlüsselt vorher,
    verschlüsselt und entschlüsselt nachher. Dazu das verwendete Passwort
    und den Salt, den Du angegeben hast (in einer geeigneten Darstellung,
    siehe unten).

    Hier:
    Unverschlüsselt:

    Salt: TestTest
    Passwort: TestTest
    Verschlüsselt:
    Test.txt
    Wieder entschlüsselt:


    Kannst Du auch beschreiben, wie Du Passwort und Salt in Key und IV umwandelst?

    Siehe hier: vbarchiv.net/tipps/tipp_2285-a…ing-verschluesselung.html

    Bzw. hier:

    VB.NET-Quellcode

    1. ' Algorithmus initialisieren:
    2. AES.Key = GenerierterKey.GetBytes(AES.KeySize \ 8)
    3. AES.IV = GenerierterKey.GetBytes(AES.BlockSize \ 8)


    Das Einfachste ist wahrscheinlich, die Video-Dateien vorher zu zippen, weil Zip-Archive nämlich keine Probleme bereiten :thumbsup:

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „ImTheOne“ ()

    ImTheOne schrieb:

    System.Windows.Forms.Application.DoEvents()
    Sieht jeglicher Quellcode von dir so aus? jede Zweite zeile ist ein DoEvents? Das ist furchtbar. Man kann DoEvents benutzten, keine Frage, aber man muss es nicht gleich missbrauchen. Zudem wirst du damit bei einer langen rechen oder verschlüsselungsoperation kein Einfrieren verhindern. Es gibt mit Tasks, Threadpools, oder dem async/await viel schönere Methoden um ein einfrieren zu verhindern. Zudem ist nicht für jede Zeile ein Kommentar nötig.
    Was ich mich noch Frage is, warum du Subs statt Funktionen nutzt. Du nutzt im Moment zwei globale Variablen, die dazu noch seltsam benannt sind(EncrypedString ist ein Byte()). Ich würde dir raten, dass du mal des Ganze VB6-Zeugs rauswirfst und dazu das Ganze in nem Nebenthread laufen lässt und so des ganze DoEvents ersetzt. Dadurch wird der Code kürzer, übersichtlicher und du lernst sogar noch was dazu.

    LG
    Sieht jeglicher Quellcode von dir so aus? jede Zweite zeile ist ein DoEvents? Das ist furchtbar. Man kann DoEvents benutzten, keine Frage, aber man muss es nicht gleich missbrauchen.

    Nein, nur, dass die Form responsiv bleibt...
    Zudem wirst du damit bei einer langen rechen oder verschlüsselungsoperation kein Einfrieren verhindern.

    Das nicht, aber die Form bleibt wenigstens verschiebbar, auch wenn sie einfriert...
    Es gibt mit Tasks, Threadpools, oder dem async/await viel schönere Methoden um ein einfrieren zu verhindern.

    Wie gesagt, mit Multithreading/ Multitasking in VB.Net kenn ich mich leider nicht aus
    Was ich mich noch Frage is, warum du Subs statt Funktionen nutzt.

    Ja, VB6-Einfluss hald ;)
    Du nutzt im Moment zwei globale Variablen, die dazu noch seltsam benannt sind(EncrypedString ist ein Byte())

    Okay, das passiert, wenn man Code von anderen Leuten kopiert und abändert :D

    P.S. Falls jemand die Software trotzdem brauchen sollte: sourceforge.net/projects/aesfilecryptor23/

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ImTheOne“ ()

    Ich glaube es wäre angebracht, dass du dir VBnet nochmal richtig aneignest, denn VB6 ist veraltet und verhält sich anders als VBnet. Wenn du in etwas keine Erfahrung hast, dann solltest du das doch lernen, oder? Threading ist kein Hexenwerk, nur ein bis zwei Stunden aneignen.

    LG
    allerdings hat Threading mit dem angefragten Problem ja nix zu tun.
    Meiner Meinung rührt die Fehldarstellung daher, dass die Datei in Blöcke zerlegt wird, und jeder einzelne Block wird extra verschlüsselt.
    Dabei ist das Instrumentarium im System.Cryptography-Namespace dazu vorgesehen, gleich den ganzen Stream in einem Stück zu verschlüsseln (das in Blöcke unterteilen und zusammensetzen geschieht intern).
    Also bevor der TE sich ühaupt ans Threading macht, sollte er sich mit Streaming-Konzepten vertraut machen.
    Achja, und Application.DoEvents() ist kein Threading, und soll auch extra-fiese Bugs verursachen können. Nämlich selten(!) auftretende Deadlocks. Und das Problem daran ist die Seltenheit, denn diese Fehler sind eiglich garnet zu debuggen, weil man sie ühaupt nicht bewusst herbeiführen kann.
    Also Empfehlung:
    1. kein DoEvents
    2. (erstmal) kein Threading
    3. Erlernen der Streaming-Konzepte - vlt. hilft activevb.de/tipps/vbnettipps/tipp0101.html (Streaming, aber ohne Crypting)
    4. Implementieren korrekter Verschlüsselung
    5. Threading erst danach.
    allerdings hat Threading mit dem angefragten Problem ja nix zu tun.

    Ja, richtig :thumbup:
    Meiner Meinung rührt die Fehldarstellung daher, dass die Datei in Blöcke
    zerlegt wird, und jeder einzelne Block wird extra verschlüsselt.

    Dabei ist das Instrumentarium im System.Cryptography-Namespace
    dazu vorgesehen, gleich den ganzen Stream in einem Stück zu
    verschlüsseln (das in Blöcke unterteilen und zusammensetzen geschieht
    intern).

    Gut zu wissen.
    Also Empfehlung:kein DoEvents

    (erstmal) kein Threading

    Erlernen der Streaming-Konzepte - vlt. hilft activevb.de/tipps/vbnettipps/tipp0101.html (Streaming, aber ohne Crypting)

    Implementieren korrekter Verschlüsselung

    Threading erst danach.

    Ich werde mich nochmal damit beschäftigen, vielen Dank schon mal an euch alle :)

    ImTheOne schrieb:

    Subs statt Funktionen
    ...
    VB6-Einfluss
    Sorry. Das kann ich nicht akzeptieren.
    Functions gibt's sogar in VBScript.

    [OffTopic]
    Auch wenn es einige hier nicht wahrhaben wollen:
    VB6 war eine bereits sehr mächtige objektorientierte Sprache.
    msdn.microsoft.com/de-de/library/55yzhfb2(v=vs.90).aspx

    Der wesentliche Unterschied zu VB.Net ist (wen wundert's?) das Fehlen des .Net-Framework.
    Man verwendete statt dessen interne Funktionen oder WinApi-Funktionen.

    Diese internen Funktionen wurden dann (für den erleichterten Umstieg) bei .Net in den VisualBasic-Namespace übernommen und werden im Forum als "böse Funktionen" verteufelt.
    Ich würde sie eher als "überflüssig" betiteln, weil diese Funktionen in vielen .Net-Klassen bereits integriert sind und dadurch wesentlich eleganter handzuhaben.

    Und natürlich hat sich VB.Net die letzten Jahre weiterentwickelt, während VB6 eingefroren wurde.

    Dieses hier übliche VB6-Gebashe kommt wohl vor allem von Leuten, die entweder noch nie oder erst die letzten paar Jahre mit dem Programmieren komplexer Projekte konfrontiert waren.

    Auch ich habe schon vielen katastrophalen VB6-Code gesehen, aber mindestens genauso häufig VB.net-Schrott.
    Das liegt nicht an der Sprache.
    [/OffTopic]

    Ich lasse mich normalerweise nicht zu solchen Diskussionen herab, aber irgendwann musste ich es einfach loswerden.
    Und nein: Dieser Kommentar soll kein Votum für VB6 sein. Ich verwende heute natürlich auch zeitgemäßere Entwicklungsumgebungen.
    Ich wollte jedoch klarstellen, dass Aussagen zu VB6 nur zu gerne aus Ahnungslosigkeit nachgeplappert werden.

    SCNR
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    petaod schrieb:

    VB6 war eine bereits sehr mächtige objektorientierte Sprache.
    Jo, aber Vererbung war nicht möglich.
    Manche bezeichnen zwar das Implementieren von Interfaces als "Vererbung" (das war möglich), aber dabei vererbt sich ja nichts in dem Sinne, dass eine Klasse die Funktionalität einer anderen mitnutzt.

    petaod schrieb:

    Ich würde sie eher als "überflüssig" betiteln
    Jo, überflüssiges ist doch böse. INsbesondere, wenns schlechter umgesetzt ist.
    Und richtig böse wirds durch den General-Import des Microsoft.VisualBasic-Namespaces, weil dadurch drängt sich der überflüssige, suboptimale Stoff auch noch in den Vordergrund, indem Intellisense ständig dieses Zeugs vorschlägt.
    Nutzt man es dann tatsächlich, dann hat man
    1. suboptimale Methoden aufgerufen
    2. man lernt die wirklich optimalen Methoden garnicht erst kennen
    3. man lernt auch die Systematik des Frameworks nicht verstehen
    Also imo ist vb.net als OOP-Sprache nicht ernstzunehmen gegenüber c# - solange man die Visual Studio - Empfohlene Einstellungen nicht umgesetzt hat.
    Daher bin ich immer dabei, wenns drum geht, Strict Off und den "Deppen-Namespace" zu bashen :evil:

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    Strict Off und den "Deppen-Namespace"
    aus den Grundeinstellungen zu entfernen ist ja auch konstruktiv.
    Ob es aber immer gleich Bashing sein muss?
    Naja, vielleicht brauchen das manche, um es zu lernen.

    Mir wäre viel lieber, die Leute würden die Hintergründe kapieren, warum die Verwendung keinen Sinn macht (oder vielleicht halt manchmal doch), anstatt nur einen Anschiss im Hinterkopf zu haben.
    Aber vielleicht bin ich auch ein unverbesserlicher Optimist.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --