Enable Javascript


Last Arduino/ESP project (click to open)
Ster inactiefSter inactiefSter inactiefSter inactiefSter inactief
 

Artikelindex

Light SQL in .NET met anorexia
Inclusief Data en File Cryptografie met 256 bits Rijndael algoritme

SQLite of "SQL Server CE" zonder (het gehannes met) automatisch gegenereerde Database, Connention, Datasets en Queries. Met voorbeeld in Visual Basic 2008 voor Windows & Mobile, eenvoudig om te zetten in C#. Met het 256 bits Rijndael algoritme EnCrypt/DeCrypt op een data-veld toepassen. Met detectie van x86, x64AMD, x64Intel processor

Inleiding:
Bij mijn vorige project Googelde ik een enkele keer om een System.Data.SQL probleempje op te lossen. Ongelooflijk hoeveel vragen daar over zijn en hoe weinig goede/werkende/werkbare oplossingen er worden aangedragen. Zelf bij antwoorden van Microsoft-medewerkers blijf je vaak in het duister tasten. Uiteindelijk ben ik er met doorzoeken en uitproberen natuurlijk wel uitgekomen. Verder bleek mij dat de hoeveelheid informatie en juistheid er van op Forums voor C++ goed is, voor C# redelijk en voor VB zeer slecht. Een probleem is ook dat er in ADO.Net nogal wat paralleloplossingen zijn, verschillende mogelijkheden met het zelfde resultaat. Dus moet je er voor oppassen dat je niet van twee of meer walletjes tegelijk eet. Eerst begonnen met de halfautomatische VS oplossing, maar dat blijkt achteraf meer op het "met een kanon op een mug schieten". Ik wil mijn SQL database "oplossing" best met anderen delen, vandaar deze, laat ik het maar zo noemen, "Workshop". Daarnaast ook nog wat over het versleutelen van wachtwoord, data-velden en bestanden en een sterkwachtwoordgenerator. Nevenbij ook een oplossing voor de, veel geGoogelde, problemen met TextBox.Passwordchar en ComboBox in een DataGridView. Deze oplossing werkt, zonder aanpassingen, zowel bij Windows XP-SP2 t/m Win7 en Mobile 5 t/m 6.5 (dus niet Phone7). Enige kennis over/van SQL, queries, Database en programmeren in VB/C# is wel noodzakelijk, want dit is geen cursus en het "een en ander" kan vast wel beter.


Zomaar een, in de praktijk onbruikbare, database met SQLite-VB GUI als voorbeeld.

Een light SQL DB in Visual Studio 2005 - 2008 (of 2010 zonder Mobile):
In Visual Studio .NET lijkt het heel eenvoudig en makkelijk om een database te genereren en dan automatisch de Connection, Datasetsets, Adapters, BindingSources en de diverse querys te laten aanmaken door databinding in een Form.vb [Design] venster. En dat is het ook, behalve dan als je achteraf wijzigingen wilt aanbrengen in de tabellen, datatypen en queries want dan ben je "in de aap gelogeerd". Zo ook als je het progje distribueert, dan wijst de Connectionstring naar het oorspronkelijke path van jouw project. In tal van Forums staan oplossingen om dit laatste probleem, op meer of minder intelligente wijze, op te lossen. Maar ook dat blijft een heel gehannes want de oude Connection wordt steeds teruggezet of "Server Explorer" en MyDataSet.vb/xsd geven een error. Er is ook een andere, veel directere, oplossing met een heel flexibel resultaat en ook nog eens een veel kleinere EXE (bij mijn SaveMe!! 55%). Als je dan ook SQL Server CE inruilt voor SQLite (public domain) dan heb je ook nog eens minder DLLs en kan je progje ook zonder installatie overal draaien; Windows XP-SP2 t/m Win7, x86, x64AMD, x64Intel en Mobile 5-6.5 PRO.


Dit alles hebben we helemaal niet nodig en gaan we dan ook niet gebruiken

In plaats van het automatisch genereren van diverse bestanden met heel veel programmaregels kun je ook zelf een Class en/of Module schrijven. Dat vergt relatief weinig code, is zeer flexibel en onderhoudsvriendelijk en doet verder precies het zelfde. Een groot voordeel van zelf schrijven is ook dat je ook beter gaat begrijpen hoe het werkt. Op zich vind je dit ook gewoon in VS-HELP terug, daar staan namelijk diverse oplossingen voor het zelfde probleem beschreven. Het vervelende is echter dat dit nogal verspreid staat opgeslagen zodat je blijft bladeren en lezen in plaats van het programmeren.

Wat dit niet is en wat je reeds moet weten:
Dit is geen cursus programmeren, database en SQL statements ontwikkelen. Ik ga er vanuit dat de basiskennis aanwezig is. Zo nodig kun je met Googelen diverse gratis online cursussen vinden. Behoorlijk gedateerd maar heel duidelijk en nog steeds goed bruikbaar, ADO.NET: Developing Database Applications. Informatie over de opbouw van SQL-opdrachten kun je ook overal vinden, maar mijn voorkeur gaat uit naar: Uitgebreid (EN): SQL From Wikipedia, the free encyclopediaL  Beperkt (NL): SQL (Structured Query Language)

SQL Server CE (gebruik ik niet meer):
Dat is bij Visual Studio .NET inbegrepen maar heeft als nadeel dat het uit vele DLLs bestaat, nogal veel bytes nodig heeft en dat je progje zonder installatie niet zal werken. SQL Sever CE, de laatste 2 tekens zeggen het al, is oorspronkelijk bedoeld voor Windows Smart Device, maar is ook bruikbaar voor Windows XP-SP2 t/m Win7 toepassingen. De informatie in Help-MSDN (t/m 2008) is verre van compleet maar bij microsoft.com kun je wel alles vinden: SQL Server Compact 3.5 Books Online en hier ADO.NET

SQLite & SQLite.NET (mijn voorkeur, open source):
SQLite en SQLite.NET code is practisch gelijk aan SQL Server CE en ADO.NET. SQLite kun je zo op het WWW vinden en is universeel inzetbaar. Het is echter niet zomaar even in VB/C#.NET te gebruiken, er is een zogenaamde "wrapper" nodig om er confortabel mee te kunnen werken. Bij http://sqlite.phxsoftware.com/ vindt je een perfecte wrapper (System.Data.SQLite) met er bij laatste SQLite versie:

System.Data.SQLite
An open source ADO.NET provider for the SQLite database engine
There are zero licensing restrictions for private or commercial use

Na installatie van deze wrapper werkt het in Visual Studio net zo als SQL Server CE alleen moet je op een enkele plaats de namespace SqlServerCe.<nnn> vervangen door SQLite.<nnn>. Met "alles" bedoel ik ook alles, dus ook het automatisch aanmaken en het "gehannes" van een database, Connection en Datasets (dat doen we hier dus niet). Het grote voordeel van SQLite is dat je progje slechts één SQL-DLL nodig heeft en je het zonder installatie kunt gebruiken. Bij Windows Mobile sluit je 2 DLLs bij. Helaas heeft men aparte DLLs voor 32 en 64 bits systemen gecompileerd, x86, x64AMD en x64Intel. Daardoor moet je bij distributie van je progje altijd 3 DLLs bijsluiten en er voor zorgen dat de juiste wordt gebruikt. Ook daar vindt je hier een programmatische oplossing voor zodat gebruikers hier geen hinder van ondervinden.

SQLite Administrator (database opzetten, freeware):
Dit is een zeer eenvoudig te gebruiken en redelijk goed hulpje om je tabellen te ontwerpen en te wijzigen. Je vindt het hier http://sqliteadmin.orbmu2k.de/ Hierin maak je je database met tabel(len) welke je dan in je toepassing gaat gebruiken. Achteraf aanpassen is simpel en je kunt eventueel ook data invoeren en bewerken. Het is nog Beta, maar ik kwam alleen maar een paar schoonheidfoutjes tegen.

Van VB naar C#:
Hier http://www.developerfusion.com/tools/convert/vb-to-csharp/ gaat dat perfect. Klik wel 2 x op copy to clipboard want soms.... Waarom in VB? Het WWW staat vol met C++ en C# oplossingen, voor VB is dat nogal beperkt. Conversie van VB naar C# gaat probleemloos en moet voor een beetje C Sharper een zachtgekookt eitje zijn.

Welke zaken zijn nodig om met je database te kunnen werken:
Eigenlijk net als bij het automatisch genereren: Connection, DataSet, Adapter, DataTable en als je Controls aan data wilt binden ook nog een BindingSource met Event. Een DataRow per tabel is extra, meer daarover volgt later. Het verschil is alleen dat je ze zelf declareert en ook zelf bepaald wat je ermee gaat doen. Dat bespaart je een enorme hoeveelheid, automatisch gegenereerde, onoverzichtelijke code.


Voorbeeld uit mijn SaveMe!! project
Merk op dat hier een Module is gebruikt, Module of Class, dat is afhankelijk van je toepassing

Deze attributen kun je zeer flexibel inzetten en gebruiken. DataBinding aan de diverse Form-controls kun je in het Form_Load-Event programmeren. Ook DataGridView-DataSource (en aanverwante eigenschappen) kun je gewoon in je code toepassen. In plaats van DataBinding kun je ook de BindingSource-Evens benutten om Controls, al dan niet aangepast, met DB-data te vullen. Beide methoden komen in een Form aan bod.

Dezelfde module voor Windows XP-Win7 en Mobile:
Mobile gebruikt een sterk beperkte commandoset en heeft soms een wat andere notatie en parameters nodig dan je normaal voor Windows zou coderen. Door hier rekening mee te houden kun je met één module voor beide toepassingen volstaan. Wel moet Mobile een eigen exemplaar hebben daar het anders een foutmelding geeft over de versie van System.Data in Compact Framework.

Wat gaan we maken:
Een heel eenvoudige, nogal rommelige, NAW database toepassing. Dat rommelige komt omdat het gebruik van de DB module voorop staat en de NAW-toepassing helemaal niets voorstelt cq op de voorbeeldfunctie na totaal nutteloos is. Ook geen tabelverknopingen/koppelingen/....., zoals voor een relationele -database, die kun je later zelf aanbrengen door het toevoegen van de daarvoor benodigde queries (gebruik de queries in de module als voorbeeld).De volgende Classes en Modules komen aan bod:

  1. Class NawDB
    De database-Tabel-NAW procedures  en functies.
    Acties lokaal op DataSet en met SQL statements direct in DB.
  2. Module PasswordDB
    De database-Tabel-Password procedures  en functies.
    Ook een sub-Class om een BindingSource Event in een Class/Forms beschikbaar te maken.
    Daar Password uit slechts één record bestaat welke en overal gelijk moet zijn kan dit in een module worden gestopt.
  3. Module Diversen
    Wat gemeenschappelijke variabelen, functies en subroutines.
  4. Module Crypt
    256 bits Rijndeal Encrypt en Decrypt van data en bestanden
    Wachtwoordtest
  5. Form frmInitDB
    Test op 32/64bits Intel- of AMD-processor en klaarzetten van de juiste System.DataSQLite.DLL (1 uit 3 DLLs)
    Test op database aanwezig.
    Zet applicatie-Path, DB-filenaam en ConnectionString.
  6. Form frmNAW
    Demonstreren de werking van DB Module en Class.
    Beveiligde wachtwoordbeveiliging vanuit database.
    Listbox voor het snel voorzetten van een item in de TextBoxes en het DataGridView.
    DataGridView met DataGridViewTextBoxColumn.PasswordChar (*) en DataGridViewComboBoxColumn.
    Versleutelde (Encrypt)  datavelden, via het wachtwoord, SubKey en Key.

Om het eenvoudig te houden wordt er "recht toe, recht aan", met duidelijke benamingen, gecodeerd. Aan het eindeloos voorzien van Remarks heb ik een hekel, ik vind dan de code onnodig uitgerekt waardoor het onoverzichtelijk wordt. Dus probeer ik de code "voor zichzelf" te laten spreken. Ik gebruik modules om variabelen en datavelden, in meerdere Forms/Classes/Modules tegelijk, met dezelfde waarden beschikbaar te hebben. In dit geval ook voor de Password-tabel.

De programmacode:
OOPs, ik ben ik niet eigenwijs, maar doe het wel op mijn eigen wijze! De Experts zullen wel de nodige bedenkingen hebben daar dit allemaal nu niet bepaald een OOP codering is. Ook zijn er Functions en Subs welke algemener bruikbaar zouden kunnen zijn. En daar hebben ze dan ook volkomen gelijk in. Maar dat OOP een must is, dat tijdperk, daar ben ik allang overheen. Soms is lekker ouderwets "recht toe, recht aan" programmeren ook een goede oplossing. Natuurlijk moet je de vroegere assembler en MS-Basic spaghetti's vergeten, maar zo kan het ook goed en onderhoudsvriendelijk zijn.
Maar... zo, op mijn eigen wijze dus, is het wat sneller, kleiner en toch overzichtelijk. Dus ook makkelijk aan te passen en vooral dat laatste, dat is hier belangrijk. En als Expert kun je er alsnog echte OOP van maken; toch...
Info: Over spaghetti gesproken, ik ben in 1976 met Motorola 6800 machinetaal begonnen, daarna de "hogere talen" 68nn en 6502 assembler. Hoe men (we) toentertijd de code "verbeterde" en uitbreide, dat was op de duur totaal onleesbaar door het achteraf tussengevoegd heen en weer springen.

Het al dan niet delen van één database met Windows XP-Win7 en Mobile:
Het delen gaat eenvoudig zo: Al de volgende mappen en bestanden op één geheugenkaartje of USB-stick en het is universeel te gebruiken.

  1. Map NAW
    Snelkoppeling naar Mobile\NAW.EXE (in PDA/Smartphone aanmaken)
    Snelkoppeling naar Windows\NAW.EXE (in Windows aanmaken)
    1. Map Database
      NAW.s3db (het database-bestand)
    2. Map Mobile
      NAW.EXE (GUI aangepast aan PDA/Smartphone en zonder Form frmInitDB)
      SQLite.Interop.dll
      System.Data.SQLite.dll
    3. Map Windows
      NAW.EXE
      System.Data.SQLite.AMD64.dll
      System.Data.SQLite.IA64.dll
      System.Data.SQLite.x86.dll
      (Form InitDB kiest de juiste DLL en kopieert deze dan als System.Data.SQLite.dll)

Zonder Mobile sla je punt 2 over, zonder Windows sla je punt 3 over. In die gevallen zou je ook de database  in de map bij de EXE kunnen plaatsen, dan moet je bij Form InitDB een aanpassing in de code maken bv DbPath = AppPath.
Als je het in een Windows-system-folder zet dan moet je voor de map Database en het bestand NAW.s3db de rechten voor schrijven aanpassen (of NAW.s3db in een documentenmap plaatsen en in het programma het path aanpassen).
LET OP de namen van de SQLite-DLLs!
SQLite.NET komt met diverse processor-Folders met daarin steeds een voor die processor specifieke System.Data.SQLite.dll.
Deze moet je zelf van de juiste namen voorzien (zie bij Map Windows hierboven).
Voor mobiele moet je SQLite.Interop.nnn.dll (nnn staat voor een getal bv. 066) wijzigen in SQLite.Interop.dll.
SQLite-foutmeldingen tijdens het opstarten zijn meestal aan een verkeerde DLL te wijten.


Na installatie van SQLite.NET vindt je hier de diverse DLLs.

Geen Demo-Download:
Gewoon "op je eigen wijze"gebruik maken van het voorbeeld en eventueel wat code kopiëren en plakken. dan weet je waar je mee bezig bent.


Database

De database:
Dat NWA (Naam, Adres, Woonplaats) database moet je niet serieus nemen, dit demo object moest toch een naam hebben.
Opslaan op een plaats naar keuze, ik kies voor Desktop, later plaatsen we twee kopieën in de VS .NET NAW Solution-Projecten. Open SQLite Administrator (Access of wat anders kan natuurlijk ook maar geeft waarschijnlijk ook meer bytes aan overhead) en maak de benodigde velden aan. In de 2e afb. staan al de velden met hun opties opgesomd (aangemaakt als in 1e afb.). Zoals je ziet is het in de praktijk niet echt bruikbaar maar voor deze demo ruim voldoende. Het veld Geheim, lengte 200 tekens, wordt voor het versleutelen gebruikt, blijft hier leeg en zit er nog even voor "spek en bonen" bij. Voor het gemak vul je gelijk wat records met je eigen data. Ik doe dat hier nogal fantasieloos maar wel makkelijk herkenbaar in de demo.
Het veld ID heeft hier maar een zeer beperkte functie maar is bij het verknopingen van tabellen onontbeerlijk (doen we hier niet aan). Maak nog een tabel aan met de naam Password met de velden Password en SubKey, elk met een lengte van 200 tekens (4e afb.). De waarden voor de velden Password en Subkey zijn in eenmalige programmacode aangemaakt:


' ''zo genereer je de eerste keer de waarden Password en SubKey
' ''voor in de Tabel Password
Dim Password As String = "0000"
Dim PasswordEncrypt As String = Encrypt(Password, Password)
' '' PasswordEncrypt: QZDIeuvQRZHlbi/Wl03y1w==
' ''                  ------------------------
Dim Subkey As String = "p|+I]{+IK3u%XqV+8|7h>%<e"
Dim SubkeyEncrypt As String = Encrypt(Subkey, Password)
' ''SubkeyEncrypt: 0RMMpQhV0lr6rrDDIH9GdSnv2yGemF8hjygr0YVJ+yyGnfZSI1kAbPBPowjIdWv6zgYFteNca1U5B0pWDGCJBg==
' ''               ----------------------------------------------------------------------------------------

Zoals je ziet is het wachtwoord met zichzelf versleuteld en de SubKey met het wachtwoord. De SubKey wordt samen met de Crypt-Key gebruikt om de datavelden "Geheim" te ver- en ontsleutelen. Als het wachtwoord wordt gewijzigd moet dus eerst de SubKey worden ontsleutelt om het dan met het nieuwe password opnieuw te versleutelen. Zie laatste afbeelding waar PasswordEncrypt en SubkeyEncrypt te plakken


Tabel en kolommen aanmaken...


ID = Prim.Key en auto-increment.
50 tekens per tekstveld is wel genoeg, Geheim 200 en Homepage 260.
De waarde van Relatiesoort komt later met ook tekst in een DataGridView Combobox.


Geheim blijft hier nog even geheim, in Textbox en DataGridView.columns wordt het met en zonder *-tjes weergegeven.


Er is een veld Password en SubKey nodig om de velden Geheim te ver- en ontsleutelen.
PasswordEncrypt (kopiëren en in veld Password plakken):
QZDIeuvQRZHlbi/Wl03y1w==
SubKeyEncrypt (kopiëren en in veld SubKey plakken):
0RMMpQhV0lr6rrDDIH9GdSnv2yGemF8hjygr0YVJ+yyGnfZSI1kAbPBPowjIdWv6zgYFteNca1U5B0pWDGCJBg==

Het versleutelde wachtwoord in de database is veilig. Als je het wachtwoord zomaar in de database of programmacode zet dan is het heel eenvoudig te achterhalen. Indien SubKey of, in Module Crypt, Key en/of IV worden gewijzigd dan is het wachtwoord onbruikbaar en geeft Decrypt een fout en blijven voortaan alle geheimen ook echt geheim. Dat laatste geld ook als het wachtwoord, na de eerste keer wijzigen, wordt vergeten. Tijdens DEBUGen kan het wachtwoord en de SubKey automatisch op boven vermelde waarden worden gereset met de procedure PasswordEnSubKeyReset() in Module PasswordDB.

TIP

Als je toch een database in je toepassing gebruikt kun je daar ook tabellen bij maken voor de opstartgegevens, talen,.
... en wat je nog meer kunt bedenken. Bij talen stopt je al je control-teksten, zoals van labels/knoppen/...., van één taal in één record. Via DataBinding of een BindinSourceEvent hang je de velden aan de juiste data-Column. Als van taal-record wordt gewisseld worden de schermteksten automatisch aangepast. Eventueel laat je de gebruiker zijn eigen schermteksten ingeven.


Project

Project:
Gelijk maar voor Windows en Mobile. Als je Mobile niet gebruikt kun je het Project NawMOB ook weglaten. Het kan zijn dat je in Visual Studio een Update moet doen naar Mobile 5, 6 en 6.5, het is bij Microsoft gratis te downloaden. Mobile (Smart Device Development) gebruikt haar eigen NawDB/PasswordDB/Crypt/Diversen, maar die zijn exact gelijk aan die voor Windows. De reden is dat er geen extra DLL ontstaat en omdat NawDB en PasswordDB de Compact Framework versie van System.Data nodig hebben. Daar de in Mobile te gebruiken opdrachten ook in de Windows-versie functioneren kun je de 4 bestanden simpelweg importeren.
Het Form frmDbInit is alleen voor de Windows-versie. De Forms frmNAW en frmNawMOB zijn aan code en controls voor ruim 90% gelijk. Het  Mobile Form frmNawMOB laat ik aan je zelf over want 1 op 1 overzetten past niet op alle PDA/Smartphone-schermpjes. De gewenste Controls en prog.code kun bij Form frmNAW kopiëren en dan in frmNawMOB  plakken, daarna wat aanpassingen maken. Welke aanpassingen: volg de lijst in het Errors venster (zijn er maar een paar en het is ook niet moeilijk) en de rest merk je wel bij het testen.


NAW is het Windows Project
NawMOB is het Smart Device Project


Met juiste Form starten en t/m het laatste Form open houden.



Nu nog even de Database erbij plaatsen...


...en de DLLs.
In de Debug en Release mappen van NawMOB zijn ze niet nodig
maar het is wel makkelijk als ze daar "kant & klaar" staan (zie hieronder).

Met deze Project instellingen en bestanden zou het, als de prog.code en controls er in zitten, moeten werken ;-)

Mobile Debugging:
Device Emulator en PDA/Smartphone


Na de eerste keer "Start Debugging (F5)" wordt map NAW aangemaakt en volg er een foutmelding.
1) Maak map Database en kopieer de DB er in.
2) Kopieer de 2 DLLs bij NAW.exe in de map.
"Start Debugging (F5)" zal nu NAW uitvoeren.

Na debugging kun je deze mapjes wissen en het, zoals eerder bij "Inleiding" omschreven, op een kaartje of stick zetten.


lsNawDB

clsNawDB:
Hier staat of valt je database-toepassing mee. Dit is, wat database betreft, een redelijk eenvoudige Class. Maar als je de werking ervan door hebt dan toets je zo een gecompliceerde module in elkaar, want het is in principe allemaal ongeveer het zelfde. Voorwaarde is dan wel dat je goede SQL queries kunt bouwen. Deze Class bevat de belangrijkste elementen voor de communicatie tussen DB-bestand en GUI. Er staan lokaal werkende acties in en directe, in de DB werkende, SQL acties in. Beide hebben het nadeel dat ze maar in één richting de gegevens bewerken; of alleen in de DB - of alleen in de GUI. In beide gevallen is het dus zaak om om de andere zijde te Updaten. Lokale acties zijn wat sneller maar ook minder zeker omdat, bij storing of verkeerd afsluiten, wijzigingen niet direct in de DB worden doorgevoerd en dan verloren gaan. Met SQL-acties is praktisch elke datamanipulatie mogelijk. gewoon een kwestie van de juiste query invoegen. Hier staan alleen wat simpele queries, maar met deze als voorbeeld kun je denk ik prima vooruit. Als je het begrijpt zijn ook relationele-databewerkingen eenvoudig toe te passen. Daar clsNawDB een Class is kun je het op diverse plaatsen declareren en met eigen DB-data gebruiken. Anders is dat bij de Module modPasswordDB. Deze heeft nagenoeg dezelfde opbouw als clsNawDB maar is, ongedeclareerd, overal met dezelfde DB-data beschikbaar. Eerder zagen we al dat Database, Connection, DataSet, Adapter, DataTable, BindingSource met Event noodzakelijk zijn. Extra een DataRow per tabel (zie ook modPasswordDB) welke steeds automatisch wordt gevuld vanuit het geselecteerde record en zo eenvoudig is uit te lezen. Gebruikt ze ook voor het kopiëren van ongewijzigde waarden in queries. Enkele van deze componenten zijn als Public en anderen als Private gedeclareerd. Je ziet dus gelijk welke je ook buiten deze module kunt benutten. Om het overzichtelijk te houden is de code in logische blokken opgedeeld:

#Region "<naam>"
'' ' code blok
#End Region ' <naam>

Code welke niet door deze demo NAW GUI wordt gebruikt hoeft niet gecompileerd te worden, dat staat dan in een conditieblok:

#Const Compile = False
'#Const Compile = true

#If Compile Then
'' ' code
#End If ' compile 

Namen zijn zo gekozen dat ze, naar mijn mening, bijna voor zichzelf spreken.

Project NAW - clsNawDB.vb


Imports System.Data.SQLite

Public Class NawDB
' '' NAW-record(s) moet(en) per Form individueel beschikbaar zijn
' ''  dus staat deze in een Class

#Region "NAW"

Private _RowGetTblNAW As DataRow ' BindingSourceTblNAW.Current-Record voor uitlezen
Public ReadOnly Property RowTblNAW() As DataRow
Get
Return _RowGetTblNAW
End Get
End Property

Private Connection As New SQLiteConnection ' de connectie met het DB-bestand
Private DataSetDbNAW As DataSet = New DataSet() ' de set DB-tabellen 
Private AdapterTblNAW As SQLiteDataAdapter ' de adapter werkt direct met DB
Private DataTableTblNAW As DataTable ' de lokale tabel
Public WithEvents BindingSourceTblNAW As New BindingSource() ' binding vanuit DataTable
Public Event BindingSourceTblNAWChanged(ByVal Records As Integer) ' doorgeven van binding-Event

Public Function InitDB() As Boolean
Try
Dim i As Integer
Connection.ConnectionString = ConnectionString
      Connection.Open()
      AdapterTblNAW = New SQLiteDataAdapter("SELECT * FROM tblNAW", Connection)
      i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW")
      DataTableTblNAW = DataSetDbNAW.Tables("tblNAW")
      BindingSourceTblNAW.DataSource = DataTableTblNAW
Catch ex As Exception
Return False
End Try
Return True
End Function

Public Sub CloseDB()
Try
Dim i As Integer
i = AdapterTblNAWUpdate()
      Connection.Close()
      BindingSourceTblNAW.Dispose()
      DataTableTblNAW.Dispose()
      AdapterTblNAW.Dispose()
      DataSetDbNAW.Dispose()
      Connection.Dispose()
Catch ex As Exception
End Try
End Sub

Public Function AdapterTblNAWUpdate() As Integer
Dim cmdBuilder As SQLiteCommandBuilder
    cmdBuilder = New SQLiteCommandBuilder(AdapterTblNAW)
Return AdapterTblNAW.Update(DataSetDbNAW, "tblNAW")
End Function

Private Sub DBNullTest()
' '' Vervangt een eventueel DBNull.Value door een lege Sting
If DBNull.Value.Equals(_RowGetTblNAW("Naam")) Then _RowGetTblNAW("Naam") = ""
If DBNull.Value.Equals(_RowGetTblNAW("Adres")) Then _RowGetTblNAW("Adres") = ""
If DBNull.Value.Equals(_RowGetTblNAW("Woonplaats")) Then _RowGetTblNAW("Woonplaats") = ""
If DBNull.Value.Equals(_RowGetTblNAW("Geheim")) Then _RowGetTblNAW("Geheim") = ""
If DBNull.Value.Equals(_RowGetTblNAW("Homepage")) Then _RowGetTblNAW("Homepage") = ""
If DBNull.Value.Equals(_RowGetTblNAW("Relatiesoort")) Then _RowGetTblNAW("Relatiesoort") = 0
End Sub

Private Sub BindingSourceTblNAW_CurrentChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles BindingSourceTblNAW.CurrentChanged
' '' Vult, na wijzigen van SelectedIndexChange, _RowGetTblNAW met het huidige record
' '' Roept BindingSourceTblPassword_CurrentChanged-Event aan bij gebruikers-Class
If BindingSourceTblNAW.Count > 0 Then
' '' CType() tegen Late Binding Error in Mobile
_RowGetTblNAW = CType(BindingSourceTblNAW.Current, DataRowView).Row
      DBNullTest()
RaiseEvent BindingSourceTblNAWChanged(BindingSourceTblNAW.Count)
End If
End Sub

#End Region ' NAW
' '' ______________________________________________________________________________
' '' Acties via een DataSet:
' '' Deze zijn lokaal, dus sneller maar ook minder veilig 
' '' Vergeet je een DataAdapter.Update of ongewone beëindigen van het programma 
' ''  dan gaan de wijzigen verloren
' '' DataBinding van Controls is ook lokaal, dus moet je wijzigingen middels prog.code
' ''  in de database opslaan
' '' 
' '' Acties via een SQL statement:
' '' Deze werken direct in de database, dat is veilig maar relatief traag
' '' Zonder DataAdapter.Fill komt het niet in je DataTable terecht
' ''
' '' Het Form frmNAW gebruikt slecht 1 van onderstaande acties daar BindingSource ook
' ''  diverse mogelijkheden heeft
' '' Gebruik ze als model voor uitbreiding of andere ontwikkelingen

#Const Compile = False
'#Const Compile = true

#Region "Acties via DataSet"

#If Compile Then

Private Function UpdateInsert(ByVal ID As Integer, ByVal Naam As String, _
ByVal Adres As String, ByVal Woonplaats As String, ByVal Geheim As String, _
ByVal Homepage As String, ByVal Relatiesoort As Integer) As Boolean
' '' ID: -1 Insert, >0 Update
Dim i As Boolean = True
Try
Dim row As DataRow
If ID = -1 Then
row = DataTableTblNAW.NewRow()
Else
' '' Dit werkt zo natuurlijk alleen met een uniek veld als ID
' '' In andere gevallen gebruik je een Row(Array)
' '' Select("<naam> = '<parameter>'") is een wat anders uitziende query 
row = DataTableTblNAW.Select("ID = '" & ID & "'")(0)
End If
row("Naam") = Naam
      row("Adres") = Adres
      row("Woonplaats") = Woonplaats
      row("Geheim") = Geheim
      row("Homepage") = Homepage
      row("Relatiesoort") = Relatiesoort
Catch ex As Exception
      i = False
End Try
Return i
End Function

Public Function NAWUpdate(ByVal ID As Integer, ByVal Naam As String, ByVal Adres As String, _
ByVal Woonplaats As String, ByVal Geheim As String, ByVal Homepage As String, _
ByVal Relatiesoort As Integer) As Boolean
Return UpdateInsert(ID, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort)
End Function

Public Function NAWInsert(ByVal Naam As String, ByVal Adres As String, _
ByVal Woonplaats As String, ByVal Geheim As String, ByVal Homepage As String, _
ByVal Relatiesoort As Integer) As Boolean
Return UpdateInsert(-1, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort)
End Function

Public Function NAWDelete(ByVal ID As Integer) As Boolean
Dim i As Boolean = True
Try
' '' Dit werkt zo natuurlijk alleen met een uniek veld als ID
' '' In andere gevallen gebruik je een Row(Array)
' '' Select("<naam> = '<parameter>'") is een wat anders uitziende query 
Dim row As DataRow = DataTableTblNAW.Select("ID = '" & ID & "'")(0)
      row.Delete()
Catch ex As Exception
      i = False
End Try
Return i
End Function

#End If ' compile

#End Region ' Acties via DataSet

#Region "Acties via SQL statements"

Public Function NAWSelectSQL(ByVal Relatiesoort As Integer) As Integer
' '' Relatiesoort: -1 of 0 = alles, >0 selectief
Dim Query0 As String = "SELECT * FROM tblNAW"
Dim Query1 As String = " WHERE (Relatiesoort = @Relatiesoort)"
Dim i As Integer = 0
Try
If Relatiesoort = 0 OrElse Relatiesoort = -1 Then
AdapterTblNAW.SelectCommand.CommandText = Query0
Else
AdapterTblNAW.SelectCommand.Parameters.Add("@Relatiesoort", _
                                                   SqlDbType.Int).Value = Relatiesoort
        AdapterTblNAW.SelectCommand.CommandText = Query0 & Query1
End If
DataTableTblNAW.Clear()
      i = AdapterTblNAW.Fill(DataTableTblNAW)
Catch ex As Exception
Return -1
End Try
Return i
End Function

#If Compile Then

Private Function NAWUpdateInsertSQL(ByVal ID As Integer, ByVal Naam As String, _
ByVal Adres As String, ByVal Woonplaats As String, ByVal Geheim As String, _
ByVal Homepage As String, ByVal Relatiesoort As Integer) As Boolean
' '' ID: -1 Insert, >0 Update
Dim i As Integer = 0
Try
Dim cmd As SQLiteCommand = Connection.CreateCommand()
      cmd.Connection.Open()
Dim p As SQLiteParameter = Nothing
cmd = Connection.CreateCommand()
If ID = -1 Then
cmd.CommandText = _
"INSERT " & _
"INTO NAW (ID, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort) " & _
"VALUES (@Naam, @Adres, @Woonplaats, @Geheim, @Homepage, @Relatiesoort)"
Else
cmd.CommandText = _
"UPDATE NAW " & _
"SET Naam = @Naam, Adres = @Adres, Woonplaats = @Woonplaats, Geheim = @Geheim, " & _
"Homepage = @Homepage, Relatiesoort = @Relatiesoort " & _
"WHERE (ID = @ID)"
p = cmd.Parameters.Add("@ID", SqlDbType.Int)
        p.Value = ID
        p.SourceVersion = DataRowVersion.Original
End If
p = cmd.Parameters.Add("@Naam", SqlDbType.VarChar, 32)
      p.Value = Naam
      p.SourceVersion = DataRowVersion.Current
      p = cmd.Parameters.Add("@Adres", SqlDbType.VarChar, 32)
      p.Value = Adres
      p.SourceVersion = DataRowVersion.Current
      p = cmd.Parameters.Add("@Woonplaats", SqlDbType.VarChar, 32)
      p.Value = Woonplaats
      p.SourceVersion = DataRowVersion.Current
      p = cmd.Parameters.Add("@Geheim", SqlDbType.VarChar, 100)
      p.Value = Geheim
      p.SourceVersion = DataRowVersion.Current
      p = cmd.Parameters.Add("@Homepage", SqlDbType.VarChar, 260)
      p.Value = Homepage
      p.SourceVersion = DataRowVersion.Current
      p = cmd.Parameters.Add("@Relatiesoort", SqlDbType.Int)
      p.Value = Relatiesoort
      p.SourceVersion = DataRowVersion.Current
      i = cmd.ExecuteNonQuery()
      AdapterTblNAW.UpdateCommand = cmd
      cmd.Connection.Close()
      cmd.Dispose()
If i = 0 Then
Throw New ApplicationException()
End If
i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW")
Catch ex As Exception
Return False
End Try
Return True
End Function

Public Function NAWUpdateSQL(ByVal ID As Integer, ByVal Naam As String, _
ByVal Adres As String, ByVal Woonplaats As String, ByVal Geheim As String, _
ByVal Homepage As String, ByVal Relatiesoort As Integer) As Boolean
Return NAWUpdateInsertSQL(ID, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort)
End Function

Public Function NAWInsertSQL(ByVal Naam As String, ByVal Adres As String, _
ByVal Woonplaats As String, ByVal Geheim As String, ByVal Homepage As String, _
ByVal Relatiesoort As Integer) As Boolean
Return NAWUpdateInsertSQL(-1, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort)
End Function

Public Function NAWDeleteSQL(ByVal ID As Integer) As Boolean
Dim i As Integer = 0
Try
Dim cmd As SQLiteCommand = Connection.CreateCommand()
      cmd.Connection.Open()
Dim p As SQLiteParameter = Nothing
cmd.CommandText = _
"DELETE " & _
"FROM NAW " & _
"WHERE (ID = @ID)"
p = cmd.Parameters.Add("@ID", SqlDbType.Int, 4, "ID")
      p.Value = ID
      p.SourceVersion = DataRowVersion.Original
      i = cmd.ExecuteNonQuery()
      AdapterTblNAW.DeleteCommand = cmd
      cmd.Connection.Close()
      cmd.Dispose()
If i = 0 Then
Throw New ApplicationException()
End If
i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW")
Catch ex As Exception
      i = -1
End Try
Return i
End Function

Public Function NAWDeleteAllSQL() As Integer
' '' Opgepast!!! alles weg en niet ongedaan te maken
' '' Return: -1 niet uitgevoerd, >=0 aantal
Dim i As Integer = 0
Try
' ''Dit doen we met een query
Dim cmd As SQLiteCommand = Connection.CreateCommand()
      cmd.Connection.Open()
Dim p As SQLiteParameter = Nothing
cmd.CommandText = _
"DELETE " & _
"FROM tblNAW"
i = cmd.ExecuteNonQuery()
      AdapterTblNAW.DeleteCommand = cmd
      cmd.Connection.Close()
      cmd.Dispose()
If i = 0 Then
Throw New ApplicationException()
End If
i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW")
Catch ex As Exception
      i = -1
End Try
Return i
End Function

#End If ' compile

#End Region ' Acties via SQL statements

End Class


modPasswordDB

modPasswordDB:
Dit is, wat database betreft, een heel erg simpele module. Eerder zagen we al dat Database, Connection, DataSet, Adapter, DataTable, BindingSource met Event noodzakelijk zijn. Ik geef geen uitleg over deze standaard componenten, dat weet je vast al wel en anders zoek het even op. Extra een DataRow per tabel welke steeds automatisch wordt gevuld vanuit het geselecteerde record en zo eenvoudig is uit te lezen. Gebruikt ze ook voor het kopiëren van ongewijzigde waarden in queries. Enkele van deze componenten zijn als Public en anderen als Private gedeclareerd. Je ziet dus gelijk welke je ook buiten deze module kunt benutten.

Bestand of velden versleutelen?
Een heel bestand versleutelen maakt het bestand maar iets groter. Losse velden versleutelen kost veel ruimte (kijk bij Password en SubKey). Dus waarom zou je voor het laatste kiezen? De data uit een versleuteld bestand komt onversleuteld in het geheugen te staan en is met een geheugendump leesbaar te maken. Daarentegen staan versleutelde velden ook versleuteld in het geheugen en ontsleutel je ze alleen op het moment dat het noodzakelijk is. Het is dus een kwestie van welk beveiligingsniveau gewenst is.

Heb je de Database met een wachtwoord beveiligd?
In dat geval moet je eerst het database-wachtwoord laten ingeven voor je de Function InitDb() aanroept. En in InitDb() de Connection.ConnectionString aanpassen:

Public myDbPassword as String = "; Password=" & Me.txtDbWachtwoord.Text ' of via InputBox Connection.ConnectionString = "Data Source=" & DbPath & DbFile & myDbPassword

Indien InitDB waarde False geeft dan is myDbPassword fout. Er zijn voor het beveiligen met wachtwoord meer parameters beschikbaar, maar de default-waarden zijn SQLite voldoende en kun je, naar mijn ervaring, wel vergeten. Kijk bij SQLite-Help hoe achteraf met wachtwoord te beveiligen, of de beveiliging te verwijderen, het is nogal simpel te doen.

Let op de spaties aan het einde in de diverse query deel-regels!

Project NAW - modPasswordDB.vb


Imports System.Data.SQLite

Module PasswordDB
' '' Het Password-record telt slechts één record en is als Public Module overal beschikbaar 
' '' Taal-records, prog.waarden, .... kun je zo ook in deze/een Module stoppen
' '' Via een Sub-Clas wordt het BindingSourceTblPassword-Event doorgegeven,
' ''  dat wordt hier niet gebruikt maar is wel als voorbeeld aanwezig
' '' Werkt zonder declaratie, verder net als Class NawDB

#Region "Password"

Public RowTblPassword As DataRow ' BindingSourceTblPassword.CurrentRecord voor uitlezen 
Private Connection As New SQLiteConnection ' de connectie met het DB-bestand
Private DataSetDbNAW As DataSet = New DataSet() ' de set DB-tabellen
Private AdapterTblPassword As SQLiteDataAdapter ' de adapter werkt direct met DB
Private DataTableTblPassword As DataTable ' de lokale tabel 
Public WithEvents BindingSourceTblPassword As New BindingSource() ' binding vanuit DataTable

#If DEBUG Then
' ''                    Wachtwoord: 0000 (4 x NUL)
Private Sub PasswordEnSubKeyReset()
' '' Zet tijdens DEBUGen password op 0000 en reset de SubKey, wordt aanroepen vannuit InitDB
' '' zo genereer/herstel je de waarden van Password en SubKey in de Tabel Password
Dim Password As String = "0000"
Dim PasswordEncrypt As String = Encrypt(Password, Password)
Dim SubkeyEncrypt As String = Encrypt("p|+I]{+IK3u%XqV+8|7h>%<e", Password)
If PasswordUpdate(RowTblPassword("ID"), PasswordEncrypt, SubkeyEncrypt) Then _
                      AdapterTblPasswordUpdate() ' gelijk in DB opslaan
End Sub
#End If

Public Function InitDB() As Boolean
Dim i As Integer
Connection.ConnectionString = ConnectionString
    Connection.Open()
    AdapterTblPassword = New SQLiteDataAdapter("SELECT * FROM tblPassword", Connection)
    i = AdapterTblPassword.Fill(DataSetDbNAW, "tblPassword")
    DataTableTblPassword = DataSetDbNAW.Tables("tblPassword")
    BindingSourceTblPassword.DataSource = DataTableTblPassword
If i <> 1 Then Return False ' geen, of meer dan één, tblPassword record
#If DEBUG Then
PasswordEnSubKeyReset() ' uitschakelen met ' (REM)
#End If
Return True
End Function

Public Sub CloseDB()
Try
Dim i As Integer
i = AdapterTblPasswordUpdate()
      Connection.Close()
      BindingSourceTblPassword.Dispose()
      DataTableTblPassword.Dispose()
      AdapterTblPassword.Dispose()
      DataSetDbNAW.Dispose()
      Connection.Dispose()
Catch ex As Exception
End Try
End Sub

Public Function AdapterTblPasswordUpdate() As Integer
Dim cmdBuilder As SQLiteCommandBuilder
    cmdBuilder = New SQLiteCommandBuilder(AdapterTblPassword)
Return AdapterTblPassword.Update(DataSetDbNAW, "tblPassword")
End Function

Sub BindingSourcePassword_CurrentChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles BindingSourceTblPassword.CurrentChanged
' '' vult, na wijzigen van SelectedIndexChange, RowPassword met het huidige record
' '' roept sub-"Class BindingSourcesClass" op om een Event door te geven aan andere Classes (Forms)
If BindingSourceTblPassword.Count > 0 Then
' '' CType() tegen Late Binding Error in Mobile
RowTblPassword = CType(BindingSourceTblPassword.Current, DataRowView).Row
End If
' ''####### voorbeeld MODULE-Event
BindingSourcesEvents.BSPassword() 'Event doorgeven via sub-Class-Event
End Sub

#End Region ' Password

' '' Alleen Select * en Update nodig
' '' Zie clsNawDB voor info "Acties via DataSet" en "Acties via SQL statements"
#Region "Acties via DataSet"

Public Function PasswordUpdate(ByVal ID As Integer, ByVal Password As String, _
ByVal SubKey As String) As Boolean
' '' in dit geval het enigste record Updaten
' '' LET OP!!!! voordat je een nieuw versleuteld wachtwoord ingeeft:
' '' SubKey moet eerst met het OUDE wachtwoord worden ontsleuteld en 
' ''  met het NIEUWE wachtwoord versleutelen en dan pas het oude wachtwoord vervangen
' '' Natuurlijk kan dat hier ook maar ik geef er de voorkeur aan
' ''  om het buiten deze module te houden
Dim i As Boolean = True
Try
Dim row As DataRow = DataTableTblPassword.Select("ID = '" & ID & "'")(0)
      row("Password") = Password
      row("SubKey") = SubKey
Catch ex As Exception
      i = False
End Try
Return i
End Function

#End Region ' Acties via DataSet

#Region "Acties via SQL statements"

Public Function PasswordSelectSQL() As Integer
' '' in dit geval het enigste record Selecteren
' '' return: -1 niet uitgevoerd, >=0 gelukt
Dim Query As String = "SELECT * FROM tblPassword"
Dim i As Integer = 0
Try
AdapterTblPassword.SelectCommand.CommandText = Query
      DataTableTblPassword.Clear()
      i = AdapterTblPassword.Fill(DataTableTblPassword)
Catch ex As Exception
      i = -1
End Try
Return i
End Function
#End Region ' Acties via SQL statements

#Region "RaiseEvent-BindingSourcesClass"

' ''####### voorbeeld MODULE-Event
Public BindingSourcesEvents As New BindingSourcesClass
Public Class BindingSourcesClass
' '' geeft Events door
Public Shared Event BSPasswordCurrentChanged(ByVal count As Integer)
Public Sub BSPassword()    ' deze is eigenlijk niet nodig daar er maar één record is
RaiseEvent BSPasswordCurrentChanged(BindingSourceTblPassword.Count)
End Sub
End Class

#End Region ' RaiseEvent-BindingSourcesClass

End Module


modDiversen

modDiversen:
Wat hulpmiddelen voor algemeen gebruik.

Project NAW - modDiversen.vb


Imports System.Reflection
Imports System.IO
Imports System.Data.SQLite

Public Module Diversen
Public AppPath As String = ""
Public DbPath As String = ""
Public DbFile As String = ""
Public ConnectionString As String = ""
Public w1 As String = "" ' om wachtwoord in te verstoppen
Public w2 As String = GenerateStrongPW(32) ' om wachtwoord mee te verstoppen

' '' Voor GenerateStrongPW() en algemeen gebruik bij ingave-velden
Public Const Lettertekens As String = _
"~!@#$%^&*()_+[]{}<>?-=\,./:""| " & _
"abcdefghijklmnopqrstuvwxyz" & _
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" & _
"1234567890"

Public Function CompactDB() As Integer
' '' Compact/Compress/Vacuum 3 namen voor het zelfde doel: database opruimen
' '' Return: >=0 verschil in bytes, -1 = fout 
Try
Dim Connection As New SQLiteConnection
      Connection.ConnectionString = ConnectionString
Dim FileVoor, FileNa As Long
Dim Dir As New DirectoryInfo(DbPath)
Dim File As FileInfo() = Dir.GetFiles(DbFile)
      FileVoor = File(0).Length
Dim cmd As SQLiteCommand = Connection.CreateCommand()
      cmd.Connection.Open()
      cmd.CommandText = "VACUUM"
cmd.ExecuteNonQuery()
      cmd.Connection.Close()
      cmd.Dispose()
      File = Dir.GetFiles(DbFile)
      FileNa = File(0).Length
Return FileVoor - FileNa
Catch ex As Exception
Return -1
End Try
End Function

Public Function GetAppPath() As String
' '' Applicatie Path
' '' Kan anders maar werkt zo ook voor Mobile
Dim asm As [Assembly] = [Assembly].GetExecutingAssembly()
Return System.IO.Path.GetDirectoryName(asm.GetName().CodeBase)
End Function

Public Function GenerateStrongPW(ByVal Lengte As Integer) As String
' '' Een sterk wachtwoord van 4-32 tekens aanmaken
Select Case Lengte
Case Is < 4 : Lengte = 4
Case Is > 32 : Lengte = 32
End Select
Dim StrongPW As String = ""
Dim symb1 As String = Lettertekens.Replace(" ", "").Replace(vbCrLf, "")
For i As Integer = 1 To Lengte
Dim rand As Random = New System.Random(Guid.NewGuid().GetHashCode())
Dim teken As Integer = rand.Next(0, symb1.Length - 1)
      StrongPW &= Lettertekens.Substring(teken, 1)
Next
Return StrongPW
End Function

Public Function w4(ByVal k As String) As String
' '' Wachtwoord en SubKey staan versleuteld in het geheugen 
' '' Bewust nietszeggende namen w1, w2, w3, w4 en k
Dim w3 As String = Decrypt(w1, w2) ' lees Wachtwoord 
Return Decrypt(k, w3) ' geef SubKey k
End Function

End Module


modCrypt

modCrypt:
Met deze module kun je eenvoudig en zeer veilig losse gegevens en/of bestanden versleutelen.
    Encrypt = versleutelen
    Decrypt = ontsleutelen
Doormiddel van een zelf te wijzigen SubKey of Wachtwoord wordt, vanuit een basis Key, een unieke 256 Bits Key samengesteld.

Project NAW - modCrypt.vb


Imports System.IO
Imports System.Text
Imports System.Security.Cryptography

Public Module Crypt

' '' Encrypt/Decrypt byte-array, string en file met unieke 256 Bits Key
' '' Lossse data geeft bij een fout de string "Fout" terug
' '' Bij bestanden wordt een code geretouneerd
Private algorithm As Rijndael = Rijndael.Create()
Private Key As Byte()
Private IV As Byte() = {38, 108, 24, 216, 222, 181, 118, 68, 177, 45, 239, 211, 175, 151, 38, 77}
Const Fout As String = "(ERROR)"
#Const Compile = False
'#Const Compile = true

Public Function PasswordOk(ByVal ToDecrypt As String, ByVal Password As String) As Boolean
' '' Test password
' '' ToDecrypt: versleutelde wachtwoord
' '' Password: door gebruiker ingegeven wachtwoord
Return Decrypt(ToDecrypt, Password) <> Fout
End Function

Private Sub MakeKey(ByVal Sleutel As String)
' '' Maakt unieke Key van basis-Key en Sleutel (SubKey of Sleutel)
If Sleutel.Length > 32 Then Sleutel = Sleutel.Substring(0, 31)
Dim SleutelBytes As Byte() = Encoding.UTF8.GetBytes(Sleutel)
    Key = New Byte() {13, 28, 18, 114, 33, 100, 175, 128, 171, 216, 33, 62, 55, 189, 214, 104, _
                      241, 53, 46, 15, 99, 112, 104, 10, 6, 153, 52, 172, 86, 218, 40, 100}
    Array.Copy(SleutelBytes, Key, SleutelBytes.Length)
End Sub

#If Compile Then

Private Function Filetest(ByVal fileIn As String, ByVal fileOut As String) As Integer
' '' Return: 1 = no FileIn, 2 = user cancelled
If Not File.Exists(fileIn) Then Return 1
If File.Exists(fileOut) AndAlso MsgBox("re-write " & fileOut, _
                MsgBoxStyle.Information Or MsgBoxStyle.OkCancel) = MsgBoxResult.Cancel Then Return 2
End Function

#End If

#Region "Encrypt"

Public Function Encrypt(ByVal ToEncryptData As Byte()) As Byte()
Dim encryptedData As Byte() = Encoding.Unicode.GetBytes(Fout)
Dim MemStream As New MemoryStream()
Try
algorithm.Key = Key
      algorithm.IV = IV
Dim CryptStream As CryptoStream = New CryptoStream(MemStream, algorithm.CreateEncryptor(), _
                                                         CryptoStreamMode.Write)
      CryptStream.Write(ToEncryptData, 0, ToEncryptData.Length)
      CryptStream.Close()
      encryptedData = MemStream.ToArray()
      CryptStream.Dispose()
Return encryptedData
Catch ex As Exception
Return encryptedData
Finally
MemStream.Close()
      MemStream.Dispose()
End Try
End Function

Public Function Encrypt(ByVal ToEncryptText As String, ByVal Sleutel As String) As String
MakeKey(Sleutel)
Dim EncryptBytes As Byte() = Encoding.Unicode.GetBytes(ToEncryptText)
Dim encryptedData As Byte() = Encrypt(EncryptBytes)
Return Convert.ToBase64String(encryptedData)
End Function

#If Compile Then

Public Function Encrypt(ByVal ToEncryptData As Byte(), ByVal Sleutel As String) As Byte()
    MakeKey(Sleutel)
Return Encrypt(ToEncryptData)
End Function

Public Function Encrypt(ByVal fileIn As String, ByVal fileOut As String, _
ByVal Sleutel As String) As Integer
' '' Return: -1 = OK, 0 = read/write Error, 1 = no FileIn, 2 = user cancelled
Dim i As Integer = Filetest(fileIn, fileOut) > 0
If i > 0 Then Return i
    MakeKey(Sleutel)
Dim FileStreamIn As New FileStream(fileIn, FileMode.Open, FileAccess.Read)
Dim FileStreamOut As New FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write)
Try
algorithm.Key = Key
      algorithm.IV = IV
Dim CryptStream As CryptoStream = New CryptoStream(FileStreamOut, _
                                            algorithm.CreateEncryptor(), CryptoStreamMode.Write)
Dim bufferLen As Integer = 4096
Dim buffer As Byte() = New Byte(bufferLen - 1) {}
Dim bytesRead As Integer
Do
bytesRead = FileStreamIn.Read(buffer, 0, bufferLen)
        CryptStream.Write(buffer, 0, bytesRead)
Loop While bytesRead <> 0
      CryptStream.Close()
      CryptStream.Dispose()
Return -1
Catch ex As Exception
Return 0
Finally
FileStreamOut.Close()
      FileStreamIn.Close()
      FileStreamOut.Dispose()
      FileStreamIn.Dispose()
End Try
End Function

#End If

#End Region ' Encrypt

#Region "Decrypt"

Public Function Decrypt(ByVal ToDecryptData As Byte())
Dim decryptedData As Byte() = Encoding.Unicode.GetBytes(Fout)
Dim MemStream As New MemoryStream()
    algorithm.Key = Key
    algorithm.IV = IV
Try
Dim CryptStream As CryptoStream = New CryptoStream(MemStream, _
                                            algorithm.CreateDecryptor(), CryptoStreamMode.Write)
      CryptStream.Write(ToDecryptData, 0, ToDecryptData.Length)
      CryptStream.Close()
      decryptedData = MemStream.ToArray()
      CryptStream.Dispose()
Return decryptedData
Catch ex As Exception
Return decryptedData
Finally
MemStream.Close()
      MemStream.Dispose()
End Try
End Function

Public Function Decrypt(ByVal ToDecryptText As String, ByVal Sleutel As String) As String
Try
MakeKey(Sleutel)
Dim ToDecryptBytes As Byte() = Convert.FromBase64String(ToDecryptText)
Dim decryptedData As Byte() = Decrypt(ToDecryptBytes)
Return Encoding.Unicode.GetString(decryptedData, 0, decryptedData.Length)
Catch ex As Exception
Return Fout
End Try
End Function

#If Compile Then

Public Function Decrypt(ByVal ToDecryptData As Byte(), ByVal Sleutel As String) As Byte()
    MakeKey(Sleutel)
Return Decrypt(ToDecryptData)
End Function

Public Function Decrypt(ByVal fileIn As String, ByVal fileOut As String, _
ByVal Password As String) As Integer
' '' Return: -1 = OK, 0 = read/write Error, 1 = no FileIn, 2 = user cancelled
Dim i As Integer = Filetest(fileIn, fileOut) > 0
If i > 0 Then Return i
    MakeKey(Password)
Dim FileStreamIn As New FileStream(fileIn, FileMode.Open, FileAccess.Read)
Dim FileStreamOut As New FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write)
Try
algorithm.Key = Key
      algorithm.IV = IV
Dim CryptStream As New CryptoStream(FileStreamOut, algorithm.CreateDecryptor(), _
                                          CryptoStreamMode.Write)
Dim bufferLen As Integer = 4096
Dim buffer As Byte() = New Byte(bufferLen - 1) {}
Dim bytesRead As Integer
Do
bytesRead = FileStreamIn.Read(buffer, 0, bufferLen)
        CryptStream.Write(buffer, 0, bytesRead)
Loop While bytesRead <> 0
      CryptStream.Close()
      CryptStream.Dispose()
Return -1
Catch ex As Exception
Return 0
Finally
FileStreamOut.Close()
      FileStreamIn.Close()
      FileStreamOut.Dispose()
      FileStreamIn.Dispose()
End Try
End Function

#End If

#End Region ' Decrypt

End Module


frmDbInit

frmDbInit:
Test of er al een NAW draait, of de database aanwezig is, welke DLL moet worden klaargezet.
De Function AppPath() staat in Module Diversen.


Een nogal eenvoudig window

  • FormBorderStyle=None
  • Startposition=CenterScreen
  • Label1.Text="NAW: Init..."
  • Button1.Visible=False
  • Button1.Text="OK"

Project NAW - frmDbInit.vb


Imports System.Management

Public Class frmDbInit
Private Const cnstFile = "NAW.s3db"
Private Const cnstPath = "\Database\"

Private Sub frmDbInit_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Show()
Dim apps As Process() = Process.GetProcessesByName("NAW")
If apps.Length > 1 Then ' draait al?
Me.Label1.Text = "NAW: Already activated"
Me.Button1.Visible = True
ElseIf Not FileDB() Then ' DB ok ?
MsgBox(DbPath & DbFile & " ???", MsgBoxStyle.Critical, "ERROR")
End
Else ' DLL klaarzetten en Form NAW openen
Dim dll As String = "System.Data.SQLite." & Choose(CPU, "x86", "AMD64", "IA64") & ".dll"
If IO.File.Exists(AppPath & dll) Then
IO.File.Copy(AppPath & dll, "System.Data.SQLite.dll", True)
Else
MsgBox(AppPath & dll & " ???", MsgBoxStyle.Critical, "ERROR")
        Close()
End If
frmNAW.Show()
Me.Close()
End If
End Sub

Private Function FileDB() As Boolean
' '' DB-path/file test 
AppPath = GetAppPath().ToLower.Replace("file:\", "")
    DbPath = AppPath.Substring(0, AppPath.LastIndexOf("\")) & cnstPath
    AppPath = AppPath & "\"
DbFile = cnstFile
If Not IO.File.Exists(DbPath & DbFile) Then Return False ' geen DB
ConnectionString = "Data Source=" & DbPath & DbFile
Return True
End Function

Private Function CPU() As Integer
' '' Return:  1=x86, 2=AMD64, 3=IA64 (Intel Itanium)
' '' 32 of 64 bits installatie
Dim arch As String = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
Dim archWOW As String = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432")
Dim installatie As String = ""
Dim c As String = GetCpuArch() 'processor
If archWOW IsNot Nothing AndAlso archWOW <> "" AndAlso archWOW.Contains("64") OrElse arch.Contains("64") Then
installatie = "x64"
If c = "x64" Then
Return 2
ElseIf c = "Itanium" Then
Return 3
End If
End If
Return 1
End Function

Private Function GetCpuArch() As String
Dim scope As New ManagementScope()
Dim query As New ObjectQuery("SELECT Architecture FROM Win32_Processor")
Dim search As New ManagementObjectSearcher(scope, query)
Dim results As ManagementObjectCollection = search.[Get]()
Dim e As ManagementObjectCollection.ManagementObjectEnumerator = results.GetEnumerator()
    e.MoveNext()
Dim arch As UShort = CUShort(e.Current("Architecture"))
Select Case arch
Case 0
Return "x86"
Case 1
Return "MIPS"
Case 2
Return "Alpha"
Case 3
Return "PowerPC"
Case 6
Return "Itanium"
Case 9
Return "x64"
Case Else
Return "Unknown Architecture (WMI ID " & arch.ToString() & ")"
End Select
End Function

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' '' afbreken
Me.Close()
End Sub

End Class

frmNAW

frmNAW:
Een suggestie als voorbeeld met code om na te doen, maar misschien maak je er liever gelijk iets zinnigs van.
(afbeelding en tekst kan wat meer naar onder staan)


De Cotrol-namen zijn opgebouwd uit 3-letters voor het type control en de bijbehorende teksten/labels.
pnl, lsb, dvg, txb, lbl, btn, chb, rbn, nud
Let op bij rbn's; in Groep Relatie: rbnAllen, rbnFamilie,... in Groep Selecteer op Relatie: rbnSelectAllen, rbnSelectFamilie,.
..
In het rood wat voorbeelden, spaties en vraagteken worden niet meegenomen.
GroupBoxes en, op één na, alle Labels behouden de standaardbenaming.
Anchor gaat heel snel als je het op een selectie toepast, dat scheelt nogal wat klik of schrijfwerk.

Project NAW - frmNAW.vb


Imports System.Drawing

Public Class frmNAW

' ''####### voorbeeld met Event uit MODULE
'Private WithEvents BindingSourcesEvents As New BindingSourcesClass
'Private Sub BindingSourceTblPassword_CurrentChanged(ByVal count As Integer) _
'           Handles BindingSourcesEvents.BSPasswordCurrentChanged
'  ' ' Event-code hier
'End Sub
' ''######

Private WithEvents DB As NawDB = New NawDB ' BindingSourceTblPassword_CurrentChanged-Event
Private RelatieVlag As Integer = 0 ' RadioButtons Selectie-Realtiesoort

Private Sub frmBinding_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
Dim i As Integer
Me.Size = New Size(660, 397)
Me.MinimumSize = New Size(660, 397)
Me.MaximumSize = New Size(855, 567)
Me.pnlData.Visible = False
Me.txbEncrypt.ReadOnly = True
Me.txbRealatie.ReadOnly = True
Me.txbGeheim.PasswordChar = "*"
Me.rbnAllen.Tag = 0
Me.rbnSelectAllen.Tag = 0
Me.rbnFamilie.Tag = 1
Me.rbnSelectFamilie.Tag = 1
Me.rbnVrienden.Tag = 2
Me.rbnSelectVrienden.Tag = 2
Me.rbnZakelijk.Tag = 3
Me.rbnSelectZakelijk.Tag = 3
If Not InitDB() Then
MsgBox("Geen tblPassword-record gevonden: EINDE")
Me.Close()
End If
i = DB.InitDB()
    i = DB.NAWSelectSQL(-1)
    i = PasswordSelectSQL()
Me.LinkLabel1.Text = "www.kendziorra.nl"
' '' Inplaats van onderstaande DataBindingen kun je er ook voor kiezen om de Contols te 
' ''  vullen/updaten via het BindingSourceTblNAW_CurrentChanged-Event
Me.lsbLijst.DataSource = DB.BindingSourceTblNAW ' lijst om snel naar "Naam" zoeken
Me.lsbLijst.DisplayMember = "Naam" 'herhaal eertste letter van "Naam" tot het gezocht voor staat
Me.dgvGrid.DataSource = DB.BindingSourceTblNAW ' eerst datagridview binden, dan aanpassen
' '' Decrypt-TextBoxColomn voor ontsleutelde Geheim invoegen
Dim dataGridViewColumn As New DataGridViewTextBoxColumn()
    dataGridViewColumn.HeaderText = "Decrypt"
dataGridViewColumn.Name = "Decrypt"
Me.dgvGrid.Columns.Insert(4, dataGridViewColumn)
' '' Relatie-ComboBoxColomn voor Relatiesoort in tekst
Dim dataGridViewComboBoxColumn As New DataGridViewComboBoxColumn
    dataGridViewComboBoxColumn.HeaderText = "Relatie"
dataGridViewComboBoxColumn.Name = "Relatie"
dataGridViewComboBoxColumn.Items.AddRange("Allen", "Familie", "Vrienden", "Zakelijk")
Me.dgvGrid.Columns.Insert(8, dataGridViewComboBoxColumn)
' '' ReadOnly = True: Edit kan hier via textboxes, anders voor het Updaten
' ''  de kolommen "Decrypt"->"Geheim" en "Relatie"->"Relatiesoort" verwerken
Me.dgvGrid.ReadOnly = True
Me.dgvGrid.Columns(0).AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader
Me.dgvGrid.Columns(7).AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader
' '' Textboxes binden
Me.txbNaam.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _
"Naam", True))
Me.txbAdres.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _
"Adres", True))
Me.txbPlaats.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _
"Woonplaats", True))
Me.txbEncrypt.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _
"Geheim", True))
' '' Me.txbGeheim.Text in BindingSourceTblNAW_CurrentChanged-Event 
Me.txbHomepage.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _
"Homepage", True))
Me.txbRealatie.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _
"Relatiesoort", True))
' '' Realatie-RadioButtons in BindingSourceTblNAW_CurrentChanged-Event
End Sub

Private Sub frmBinding_FormClosing(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    OpslaanVervers(False)
    DB.CloseDB()
    CloseDB()
End Sub

Private Sub OpslaanVervers(ByVal Ververs As Boolean)
Dim i As Integer
' '' Update tabel uit TextBoxes
Dim Pos As Integer = DB.BindingSourceTblNAW.Position ' bewaar Position
DB.BindingSourceTblNAW.MovePrevious() ' wijzig Position
i = DB.AdapterTblNAWUpdate() ' Opslaan
If Ververs Then i = DB.NAWSelectSQL(RelatieVlag) ' verversen
DB.BindingSourceTblNAW.Position = Pos ' zet Position terug  
End Sub

Public Sub BindingSourceTblNAW_CurrentChanged(ByVal Records) _
Handles DB.BindingSourceTblNAWChanged
If Records > 0 Then
Me.lblRecNr.Text = (DB.BindingSourceTblNAW.Position + 1) & "/" & Records
Me.lblRecNr.Left = 193 - Me.lblRecNr.Width ' in r-bovenhoek van lijst houden
Me.rbnAllen.Checked = False
Me.rbnFamilie.Checked = False
Me.rbnVrienden.Checked = False
Me.rbnZakelijk.Checked = False
Select Case DB.RowTblNAW("Relatiesoort")
Case 0 : Me.rbnAllen.Checked = True
Case 1 : Me.rbnFamilie.Checked = True
Case 2 : Me.rbnVrienden.Checked = True
Case 3 : Me.rbnZakelijk.Checked = True
End Select
If DB.RowTblNAW("Geheim").ToString.Length Then
Me.txbGeheim.Text = Decrypt(DB.RowTblNAW("Geheim"), w4(RowTblPassword("Subkey")))
Else
Me.txbGeheim.Text = ""
End If
End If
End Sub

Private Sub txbHomepage_DragEnter(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DragEventArgs) Handles txbHomepage.DragEnter
If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then
e.Effect = DragDropEffects.Link
Else
e.Effect = DragDropEffects.None
End If
End Sub

Private Sub txbHomepage_DragDrop(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DragEventArgs) Handles txbHomepage.DragDrop
' '' Zowel een applicatie als een url kan hier worden ingesleept
' '' URL of EXE is met dubbelklik te openen
Me.txbHomepage.Text = e.Data.GetData(DataFormats.FileDrop)(0)
End Sub

Private Sub txbHomepage_DoubleClick(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles txbHomepage.DoubleClick
Try
Dim Link As String = Me.txbHomepage.Text
If Link.IndexOf("/") <> -1 AndAlso Link.IndexOf("http://", 0) = -1 Then _
                  Link = "http://" & Link ' Is het een url?
System.Diagnostics.Process.Start(Link)
Catch ex As Exception
End Try
End Sub

Private Sub textbox_KeyPress(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles txbWachtwoord.KeyPress, txbNaam.KeyPress, txbAdres.KeyPress, _
            txbPlaats.KeyPress, txbGeheim.KeyPress, txbHomepage.KeyPress, _
            txbNieuwWW.KeyPress, txbHerhaalWW.KeyPress
' '' Test op toegestane tekens
Dim i As Boolean = (Lettertekens & Chr(8)).IndexOf(e.KeyChar) >= 0
If i Then Exit Sub
e.KeyChar = Nothing
Beep()
End Sub

Private Sub textbox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles txbWachtwoord.TextChanged, txbNaam.TextChanged, txbNieuwWW.TextChanged, _
              txbHerhaalWW.TextChanged
' '' Minimale lengte = 4
' '' CType() tegen Late Binding Error in Mobile
If CType(sender, TextBox).Text.Length AndAlso CType(sender, TextBox).Text.Length < 4 Then
CType(sender, TextBox).BackColor = Color.OrangeRed
Else
CType(sender, TextBox).BackColor = Color.White
End If
If CType(sender, TextBox).Name = "txbNieuwWW" Then Me.nudTekensWW.Value = _
Me.txbNieuwWW.Text.Length
End Sub

Private Sub btnWachtwoord_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnWachtwoord.Click
If Me.btnWachtwoord.Text = "OK" Then
If Me.txbWachtwoord.Text.Length < 4 Then Exit Sub
w1 = Encrypt(Me.txbWachtwoord.Text, w2) ' bewaar wachtwoord verstopt
If PasswordOk(RowTblPassword("Password"), Me.txbWachtwoord.Text) Then
Me.pnlData.Visible = True
Me.txbWachtwoord.Enabled = False
Me.btnWachtwoord.Text = "Bescherm"
End If
Else
Me.pnlData.Visible = False
Me.txbWachtwoord.Enabled = True
Me.btnWachtwoord.Text = "OK"
End If
Me.txbWachtwoord.Text = ""
End Sub

Private Sub btnGenereerWW_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Me.txbNieuwWW.Text = GenerateStrongPW(nudTekensWW.Value)
Me.txbHerhaalWW.Text = Me.txbNieuwWW.Text()
End Sub

Private Sub btnNieuwRec_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnNieuwRec.Click
    DB.BindingSourceTblNAW.AddNew()
End Sub

Private Sub btnWisRec_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnWisRec.Click
If MsgBox("Naam: " & DB.RowTblNAW("Naam"), MsgBoxStyle.Exclamation Or _
              MsgBoxStyle.OkCancel, "RECORD WISSEN") = MsgBoxResult.Ok Then _
      DB.BindingSourceTblNAW.Remove(DB.BindingSourceTblNAW.Current)
End Sub

Private Sub btnOpslaanVerversenRec_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnOpslaan.Click, btnVervers.Click
If Me.txbGeheim.Text.Length Then
Me.txbEncrypt.Text = Encrypt(Me.txbGeheim.Text, w4(RowTblPassword("Subkey")))
Else
Me.txbGeheim.Text = ""
Me.txbEncrypt.Text = ""
End If
OpslaanVervers(True)
End Sub

Private Sub btnCompactDB_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnCompactDB.Click
    MsgBox("-" & CompactDB() & " KB", MsgBoxStyle.Information, "Compact DB")
End Sub

Private Sub rbnSelectRelatie_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles rbnSelectAllen.CheckedChanged, _
              rbnSelectFamilie.CheckedChanged, rbnSelectVrienden.CheckedChanged, _
              rbnSelectZakelijk.CheckedChanged
' '' de RelatieVlag bepaald welke records er worden geselecteerd
If Not Me.CanFocus Then Exit Sub ' eerst Form opmaken, daarna is DB pas beschikbaar
' '' CType() tegen Late Binding Error in Mobile
RelatieVlag = CType(sender, RadioButton).Tag
Dim i As Integer = DB.NAWSelectSQL(RelatieVlag)
End Sub

Private Sub rbnRelatie_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles rbnAllen.CheckedChanged, _
              rbnFamilie.CheckedChanged, rbnVrienden.CheckedChanged, rbnZakelijk.CheckedChanged
' '' CType() tegen Late Binding Error in Mobile
' '' Plaats de waarden 0 t/m 3 in het Tag-propertie van de betreffende RadioButtons
Me.txbRealatie.Text = CType(sender, RadioButton).Tag
End Sub

Private Sub chbToonGeheim_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles chbToonGeheim.CheckedChanged
If Me.chbToonGeheim.Checked Then
Me.txbGeheim.PasswordChar = ""
Else
Me.txbGeheim.PasswordChar = "*"
End If
dgvGrid.Refresh()
End Sub

Private Sub chbToonWW_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles chbToonWW.CheckedChanged
If Me.chbToonWW.Checked Then
Me.txbNieuwWW.PasswordChar = ""
Else
Me.txbNieuwWW.PasswordChar = "*"
End If
Me.txbHerhaalWW.PasswordChar = Me.txbNieuwWW.PasswordChar
End Sub

Private Sub btnOpslaanWW_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnOpslaanWW.Click
' '' Test nieuw wachtwoord 
' '' Decrypt SubKey met oude WW en Encrypt het met nieuw WW
' '' Sla WW op
If Me.txbNieuwWW.Text.Length < 4 Then Exit Sub
If Me.txbNieuwWW.Text <> Me.txbHerhaalWW.Text Then
MsgBox("Ongelijk", MsgBoxStyle.Information)
Exit Sub
End If
MsgBox("Wachtwoord: " & Me.txbNieuwWW.Text & vbCrLf & _
"Noteer wachtwoord en berg het veilig op!", MsgBoxStyle.Exclamation)
Dim SubKeyDecrypt As String = w4(RowTblPassword("Subkey")) ' ontsleutel SubKey
Dim SubKeyEncrypt As String = Encrypt(SubKeyDecrypt, Me.txbNieuwWW.Text) ' versleutel SubKey
Dim PasswordEncrypt As String = Encrypt(Me.txbNieuwWW.Text, Me.txbNieuwWW.Text)
If PasswordUpdate(RowTblPassword("ID"), PasswordEncrypt, SubKeyEncrypt) Then
AdapterTblPasswordUpdate() ' gelijk in DB opslaan
w1 = Encrypt(Me.txbNieuwWW.Text, w2) ' bewaar wachtwoord als w1 versleuteld in geheugen
Else
MsgBox("Wachtwoor en SubKey opslaan is mislukt!", MsgBoxStyle.Critical)
End If
Me.txbNieuwWW.Text = ""
Me.txbHerhaalWW.Text = ""
Me.chbToonWW.Checked = False
End Sub

Private Sub btnGenereerWW_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnGenereerWW.Click
Me.txbNieuwWW.Text = GenerateStrongPW(Me.nudTekensWW.Value)
Me.txbHerhaalWW.Text = Me.txbNieuwWW.Text
End Sub

Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) _
Handles LinkLabel1.LinkClicked
    System.Diagnostics.Process.Start("http://www.kendziorra.nl")
End Sub

Private Sub dgvGrid_CellFormatting(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) _
Handles dgvGrid.CellFormatting
If e.Value Is Nothing Then Exit Sub
Select Case e.ColumnIndex
Case 5
If Me.dgvGrid("Geheim", e.RowIndex).Value.length Then
Me.dgvGrid("Decrypt", e.RowIndex).Value = Decrypt(Me.dgvGrid("Geheim", _
                                                            e.RowIndex).Value, w4(RowTblPassword("Subkey")))
If Not Me.chbToonGeheim.Checked Then Me.dgvGrid("Decrypt", e.RowIndex).Value = _
New String("*"c, Me.dgvGrid("Decrypt", e.RowIndex).Value.Length)
End If
Case 8
Me.dgvGrid("Relatie", e.RowIndex).Value = _
                    Choose(e.Value + 1, "Allen", "Familie", "Vrienden", "Zakelijk")
End Select
End Sub

End Class


NAW.exe

NAW.exe:
Nog even wat voorbeelden van de on/mogelijkheden van NAW. Onmogelijkheden om dat dit een totaal onzinnige toepassing is. Mogelijkheden omdat er tal van kleinigheidjes in verwerkt zijn welke in andere toepassingen misschien wel van pas kunnen komen. Bij afsluiten wordt eerst de DB bijgewerkt.
(afbeelding en tekst kan wat meer naar onder staan)

Klik in lijst en type het eerste teken van de gezochte naam, herhaald dit tot de gezochte naam is geselecteerd. Alle er bij behorende velden worden direct aan de selectie aangepast. Klik op knop Bescherm en het venster is weer in de begintoestand.


Met Nieuw rec.  een leeg record toegevoegd, mijn gegevens, website, geheim en relatietype ingegeven en op Opslaan geklikt.

Zoeken doe je via de ListBox met een Klik en het (herhaald) ingeven van het eerste letterteken. Bewerken in TextBoxes en Realatie RadioButton, opslaan met de knop Opslaan. Zonder Opslaan wordt het geheim niet (opnieuw)versleuteld en alleen de oude inhoud van Encrypt in dataveld-Geheim opgeslagen. Opslaan werkt niet alleen lokaal maar update ook de DB. Bewerken zou ook in het DataViewGrid kunnen gebeuren, maar dan moet er extra code komen om het grid-veld Decrypt versleuteld in het dataveld-Geheim te plaatsen. Zo ook bij de Grid-ComboBoxes.


Ontsluierde geheimen.


SQL-Select op relatie past alles in één klik aan.

Dit is dan het einde, hopelijk heb je er wat aan!