Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Building Client/Server applications with VB.NET for secure private file sharing

3.70/5 (13 votes)
24 Nov 20057 min read 1   15.6K  
How to build secure private file sharing client/server using a freeware SDK

Introduction

Most encrypted file sharing solutions today use digital certificates, which are designed for applications where there is a large user base not known in advance. However, if someone wants to avoid the cost and the hassle of obtaining and maintaining certificates, there is another possible solution around.

In this article, a simple client/server solution is presented for secure private file sharing. The security is provided through a symmetric encryption algorithm (AES 128) with shared secret keys. It could be more efficient and practical in many situations, when small groups are established.

Before we start

Download and install the free edition of the file sharing SDK, which is free for non-commercial use (two connections).

The client/server components employ 128-bit AES encryption, without the need of SSL certificates. Instead, it uses a shared secret key, which creates an application-based virtual private network. In addition to standard FTP operations, such as upload, download, rename, delete, etc., the library also offers a number of advanced features, like opening of seekable streams on the server, remote searching for files and text, remote zip compression and decompression.

The server

Image 1

Load the sample project FileServer.sln. The server component can be accessed via its instance named FileSrv. Let's review its main properties and methods.

Starting the server

In order to start accepting connections, we have to go through the following steps:

  1. Setting the property ListenningPort to the number of the listening port. We take the value from the Settings form.
  2. If we want to establish encrypted connections, we have to set the property SecurityMode to 2, and SecretKey to the value of the crypto key, specified on the settings form.

    If we don't need encryption, we must set SecurityMode to 0.

  3. If we want to use packet compression, we must set UseCompression to True.
  4. Invoke the method Start().
    VB
    'Set the component properties
    Private Sub SetProperties()
      FileSrv.ListeningPort = Val(fSettings.txtPort.Text)
      If fSettings.txtKey.Text > "" Then
        FileSrv.SecurityMode = 2  'shared secret key
        FileSrv.SecretKey = fSettings.txtKey.Text
      Else
        FileSrv.SecurityMode = 0  'no encryption
      End If
      FileSrv.UseCompression = fSettings.chkCompress.Checked
    End Sub
    
    
    'Start the server
    Private Sub btnStart_Click(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles btnStart.Click
      If FileSrv.Start Then
        LogMsg("Server started")
      Else
        Call MsgBox("Cannot start the server!", , "Error")
      End If
      UpdateStatus()
    End Sub
    

Stopping the server

In order to stop accepting connections, we have to call the method Stop(). If we have some client currently connected, we should remove them with the method RemoveClient().

VB
'Stop the server
Private Sub btnStop_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnStop.Click
  Dim LI As ListViewItem
  Dim i As Integer

  FileSrv.Stop()

  For i = lvClients.Items.Count - 1 To 0 Step -1
    FileSrv.RemoveClient(lvClients.Items(i).Tag)
    lvClients.Items.Remove(lvClients.Items(i))
  Next i

  UpdateStatus()
  LogMsg("Server stopped")
End Sub

Adding a new connection

When a new client is connected, the event OnNewClient is fired. At this point we should get the client information (address/port) and store its handle somewhere for later use.

VB
'A new connection is available
Private Sub FileSrv_OnNewClient(ByVal sender As Object, _
            ByVal e As AxbsFileServerSDK.IBSFileSrvXEvents_OnNewClientEvent) _
            Handles FileSrv.OnNewClient
  Dim LI As ListViewItem

  LI = lvClients.Items.Add("Not signed in")
  LI.Tag = e.aHandle
  LI.SubItems.Add(FileSrv.GetClientAddress(e.aHandle))
  LI.SubItems.Add(Str(FileSrv.GetClientPort(e.aHandle)))
  LI.SubItems.Add(VB6.Format(Now, "hh:mm:ss"))
  LI.SubItems.Add("Connected")

  UpdateStatus()
  LogMsg("New connection from " + LI.SubItems.Item(1).Text + _
                             ":" + LI.SubItems.Item(2).Text)
End Sub

Removing disconnected clients

When a connected client is disconnected, the event OnClientDisconnected is fired. At this point we should release all data associated with this client.

VB
'A connection is broken
Private Sub FileSrv_OnClientDisconnected(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnClientDisconnectedEvent) _
        Handles FileSrv.OnClientDisconnected
  Dim LI As ListViewItem
  LI = ItemFromHandle(e.aHandle)
  If LI Is Nothing Then Exit Sub
  LogMsg("Disconnected " + LI.Text + " " + _
          FileSrv.GetClientAddress(e.aHandle) + _
          ":" + Str(FileSrv.GetClientPort(e.aHandle)))
  FileSrv.RemoveClient(LI.Tag)
  lvClients.Items.Remove(LI)
End Sub

Providing the user password

When a connection is established, the client immediately sends a sign-in request. In our simple implementation, we accept only the default users (Guest). That's why in the handler of the event OnNeedPassword, the asked username should always be empty, and we always pass an empty string for the password value.

VB
'A request for a password
Private Sub FileSrv_OnNeedPassword1(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedPasswordEvent) _
        Handles FileSrv.OnNeedPassword
  If e.aUsername = "" Then
    'this is the user Guest
    e.aOkay = True
  Else
    'Unknown user, we accept only Guest
    e.aOkay = False
  End If
End Sub

Signing in

After checking the password, the server component fires the event OnSignin. Since that moment, the client can perform various file operations.

VB
'A user is signed-in
Private Sub FileSrv_OnSignin(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnSigninEvent) _
        Handles FileSrv.OnSignin
  Dim S As String
  Dim LI As ListViewItem

  S = GetUsername(e.aHandle)
  LI = ItemFromHandle(e.aHandle)
  If Not (LI Is Nothing) Then
    LI.Text = S
  End If

  S = S + " " + FileSrv.GetClientAddress(e.aHandle) + _
      ":" + FileSrv.GetClientPort(e.aHandle)
  If e.aCode = 0 Then
    S = S + " signed in successfully"
  Else
    S = S + " failed sign-in"
  End If

  LogMsg(S)
End Sub

Listing the folder contents

The first thing which the client does after the signing in, is to get the (main) folder content. The handler of the event OnNeedListFolder is responsible to grant or refuse a permission for the operation. There are two input and two output parameters:

  • aHandle - Handle of the client object firing the event.
  • aPath - Relative pathname of the folder of interest.
  • aOkay - Set this variable to True in order to permit the operation.
  • aRoot - If the operation is permitted, write here the root folder assigned to this user.
VB
'A request to list the folder contents
Private Sub FileSrv_OnNeedListFolder(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedListFolderEvent) _
        Handles FileSrv.OnNeedListFolder
  e.aOkay = True
  e.aRoot = App_Path()
  LogMsg(GetUsername(e.aHandle) + ": list folder " + PreSlash(e.aPath))
End Sub

The end of the listing operation is signaled with the event OnListFolderDone.

Handling of "create folder" requests

When a "create folder" request is received from the client, the event OnNeedCreateFolder is fired. The handler must grant or refuse a permission for the operation. The parameters are:

  • aHandle - Handle of the client object firing the event.
  • aPath - Relative pathname of the file to be zipped.
  • aOkay - Set this variable to True in order to permit the operation.
  • aRoot - If the operation is permitted, write here the root folder assigned to this user.
VB
'A request to create a folder
Private Sub FileSrv_OnNeedCreateFolder(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedCreateFolderEvent) _
        Handles FileSrv.OnNeedCreateFolder
  e.aOkay = True
  e.aRoot = App_Path()
  LogMsg(GetUsername(e.aHandle) + ": create folder " + PreSlash(e.aPath))
End Sub

Handling of "rename file" requests

When a "rename file" request is received from the client, the event OnNeedRenameFile is fired. The handler must grant or refuse a permission for the operation. The parameters are:

  • aHandle - Handle of the client object firing the event.
  • aPath - Relative pathname of the file to be renamed.
  • aOkay - Set this variable to True in order to permit the operation.
  • aRoot - If the operation is permitted, write here the root folder assigned to this user.
VB
'A request to rename a file
Private Sub FileSrv_OnNeedRenameFile(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedRenameFileEvent) _
        Handles FileSrv.OnNeedRenameFile
  e.aOkay = True
  e.aRoot = App_Path()
  LogMsg(GetUsername(e.aHandle) + ": rename file " + PreSlash(e.aPath))
End Sub

Handling of "delete file" requests

When a "delete file" request is received from the client, the event OnNeedDeleteFile is fired. The handler must grant or refuse a permission for the operation. The parameters are:

  • aHandle - Handle of the client object firing the event.
  • aPath - Relative pathname of the file to be deleted.
  • aOkay - Set this variable to True in order to permit the operation.
  • aRoot - If the operation is permitted, write here the root folder assigned to this user.
VB
'A request to delete a file
Private Sub FileSrv_OnNeedDeleteFile(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedDeleteFileEvent) _
        Handles FileSrv.OnNeedDeleteFile
  e.aOkay = True
  e.aRoot = App_Path()
  LogMsg(GetUsername(e.aHandle) + ": delete file " + PreSlash(e.aPath))
End Sub

Handling of download requests

When a download request is received from the client, the event OnNeedDownload is fired. The handler must grant or refuse a permission for the operation. The parameters are:

  • aHandle - Handle of the client object firing the event.
  • aPath - Relative pathname of the file to be downloaded.
  • aOkay - Set this variable to True in order to permit the operation.
  • aRoot - If the operation is permitted, write here the root folder assigned to this user.
VB
'A request to download
Private Sub FileSrv_OnNeedDownload(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedDownloadEvent) _
        Handles FileSrv.OnNeedDownload
  e.aOkay = True
  e.aRoot = App_Path()
  LogMsg(GetUsername(e.aHandle) + ": start downloading " + PreSlash(e.aPath))
End Sub

The event OnDownloadDone informs about the end of the operation.

VB
'The download operation is completed
Private Sub FileSrv_OnDownloadDone(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnDownloadDoneEvent) _
        Handles FileSrv.OnDownloadDone
  LogMsg(GetUsername(e.aHandle) + ": finish downloading ")
End Sub

Handling of upload requests

When an upload request is received from the client, the event OnNeedUpload is fired. The handler must grant or refuse a permission for the operation. The parameters are:

  • aHandle - Handle of the client object firing the event.
  • aPath - Relative pathname of the file of interest.
  • aOkay - Set this variable to True in order to permit the operation.
  • aRoot - If the operation is permitted, write here the root folder assigned to this user.
VB
'A request to upload
Private Sub FileSrv_OnNeedUpload(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedUploadEvent) _
        Handles FileSrv.OnNeedUpload
  e.aOkay = True
  e.aRoot = App_Path()
  LogMsg(GetUsername(e.aHandle) + ": start uploading " + PreSlash(e.aPath))
End Sub

The event OnUploadDone informs about the end of the operation.

VB
'The upload operation is completed
Private Sub FileSrv_OnUploadDone(ByVal sender As Object, ByVal e As _
        AxbsFileServerSDK.IBSFileSrvXEvents_OnUploadDoneEvent) _
        Handles FileSrv.OnUploadDone
  LogMsg(GetUsername(e.aHandle) + ": finish uploading ")
End Sub

The client

Image 2

Load the sample project FileClient.sln. The client component can be accessed via its instance FileCln. Let's review its main properties and methods.

Connecting to the server

In order to establish a new connection to the server, we have to go through the following steps:

  1. If we want encrypted connections, we have to set the property SecurityMode to 2, and SecretKey to the value of the crypto key, specified on the "Connect" form.

    If we don't need encryption, we just set SecurityMode to 0.

  2. If we want to use packet compression, we must set the property UseCompression to True.
  3. Invoke the method Connect(Addr, Port), passing as parameters the IP address/Domain name and the listening port of the server.
    VB
    'Initiate a connection request
    Private Sub btnConnect_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnConnect.Click
      If fConnect.ShowDialog <> DialogResult.OK Then Exit Sub
    
      If fConnect.txtKey.Text() > "" Then
        FileCln.SecurityMode = 2  'shared secret key
        FileCln.SecretKey = fConnect.txtKey.Text
      Else
        FileCln.SecurityMode = 0  ' no encryption
      End If
      If Not FileCln.Connect(fConnect.txtHost.Text, _
                     Val(fConnect.txtPort.Text)) Then
        MsgBox("Error Code: " + Str(FileCln.LastError))
      End If
    
      UpdateStatus()
    End Sub

Disconnecting from the server

In order to end a connection to the server, we have to call the method Disconnect().

VB
'Disconnect from the server
Private Sub btnDisconnect_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnDisconnect.Click
  If Not FileCln.Connected Then Exit Sub
  FileCln.Disconnect()
  Call DoDisconnected()
End Sub

Listing folder contents

The method ListFolder() sends a request for the folder contents.

VB
'Request the folder contents
Private Sub ListFolder()
  If NowList Then Exit Sub
  If FileCln.ListFolder(txtFolder.Text) Then
    NowList = True
    lvFiles.Items.Clear()
    btnList.Enabled = False
    If txtFolder.Text > "\" Then
      Call DoHaveListItem("..", True, 0, 0, 0, 0)
    End If
  Else
    CheckError(FileCln.LastError)
  End If
End Sub

The event OnHaveListItem is fired for each available folder item.

VB
'Process a list item
Private Sub DoHaveListItem(ByVal aName As String, _
            ByVal aFolder As Boolean, ByVal aLoSize As Long, _
            ByVal aHiSize As Long, _
            ByVal aLoTime As Long, ByVal aHiTime As Long)
    Dim LI As ListViewItem
    Dim ft As FILETIME
    Dim Dt As Date

    LI = lvFiles.Items.Add(aName)
    If aFolder Then
      LI.ImageIndex = FolderImgIdx
      LI.SubItems.Add(" ")
    Else
      LI.ImageIndex = FileImgIdx
      LI.SubItems.Add(Str(aLoSize))
    End If

    ft.dwHighDateTime = aHiTime
    ft.dwLowDateTime = aLoTime
    Dt = FileTimeToDate(ft)
    LI.SubItems.Add(Dt)
End Sub

The end of the list is signaled with the event OnListFolderDone().

VB
'End of the list
Private Sub FileCln_OnListFolderDone(ByVal sender As Object, ByVal e As _
        AxbsFileClientSDK.IBSFileClnXEvents_OnListFolderDoneEvent) _
        Handles FileCln.OnListFolderDone
  NowList = False
  'CheckError(aCode)
  UpdateButtons()
End Sub

Creating a new folder

The method CreateFolder() sends a request to create a new folder.

VB
'Request a new folder
Private Sub btnNew_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnNew.Click
  Dim Nm As String
  Nm = InputBox("Folder name:", "Create folder")
  If Nm = "" Then Exit Sub
  If FileCln.CreateFolder(AddSlash(txtFolder.Text) + Nm) Then
    NowCreate = True
  Else
    CheckError(FileCln.LastError)
  End If
  UpdateButtons()
End Sub

The event OnCreateFolderDone() is fired when the folder is created.

VB
'A new folder is created
Private Sub FileCln_OnCreateFolderDone(ByVal sender As Object, ByVal e As _
        AxbsFileClientSDK.IBSFileClnXEvents_OnCreateFolderDoneEvent) _
        Handles FileCln.OnCreateFolderDone
  NowCreate = False
  CheckError(e.aCode)
  UpdateButtons()
  If e.aCode > 0 Then Exit Sub
  Call ListFolder()
End Sub

Renaming a file

The method RenameFile() sends a request to rename a file on the server.

VB
'Send rename request
Private Sub btnRename_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnRename.Click
  Dim Nm As String

  If lvFiles.SelectedItems.Count = 0 Then Exit Sub
  If lvFiles.SelectedItems(0).ImageIndex = FolderImgIdx Then
    'it is a folder
    Nm = InputBox("New name:", "Rename folder")
    If Nm = "" Then Exit Sub
    If FileCln.RenameFolder(AddSlash(txtFolder.Text) + _
               lvFiles.SelectedItems(0).Text, _
               AddSlash(txtFolder.Text) + Nm) Then
      NowRenameFolder = True
    Else
      CheckError(FileCln.LastError)
    End If
  Else
    'it is a file
    Nm = InputBox("New name:", "Rename file")
    If Nm = "" Then Exit Sub
    If FileCln.RenameFile(AddSlash(txtFolder.Text) + _
               lvFiles.SelectedItems(0).Text, _
               AddSlash(txtFolder.Text) + Nm) Then
      NowRenameFile = True
    Else
      CheckError(FileCln.LastError)
    End If
  End If
  Call UpdateButtons()
End Sub

The event OnRenameFileDone() is fired when the confirmation is received.

VB
'A file is renamed
Private Sub FileCln_OnRenameFileDone(ByVal sender As Object, ByVal e As _
        AxbsFileClientSDK.IBSFileClnXEvents_OnRenameFileDoneEvent) _
        Handles FileCln.OnRenameFileDone
  NowRenameFile = False
  CheckError(e.aCode)
  Call UpdateButtons()
  If e.aCode > 0 Then Exit Sub
  Call ListFolder()
End Sub

Deleting a file

The method DeleteFile() sends a requests to delete a file.

VB
'Send delete request
Private Sub btnDelete_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnDelete.Click
  If lvFiles.SelectedItems.Count = 0 Then Exit Sub
  If lvFiles.SelectedItems(0).ImageIndex = FolderImgIdx Then
    'it is a folder
    If FileCln.DeleteFolder(AddSlash(txtFolder.Text) + _
               lvFiles.SelectedItems(0).Text) Then
      NowDeleteFolder = True
    Else
      CheckError(FileCln.LastError)
    End If
  Else
    'it is a file
    If FileCln.DeleteFile(AddSlash(txtFolder.Text) + _
                   lvFiles.SelectedItems(0).Text) Then
      NowDeleteFile = True
    Else
      CheckError(FileCln.LastError)
    End If
  End If
  Call UpdateButtons()
End Sub

The event OnDeleteFileDone() is fired when the confirmation is received.

VB
'A file is deleted
Private Sub FileCln_OnDeleteFileDone(ByVal sender As Object, ByVal e As _
        AxbsFileClientSDK.IBSFileClnXEvents_OnDeleteFileDoneEvent) _
        Handles FileCln.OnDeleteFileDone
  NowDeleteFile = False
  CheckError(e.aCode)
  Call UpdateButtons()
  If e.aCode > 0 Then Exit Sub
  Call ListFolder()
End Sub

Downloading a file

The method Download() sends a request to download a file.

VB
'Send download request
Private Sub GoDownload()
  If lvFiles.SelectedItems.Count = 0 Then Exit Sub
  If lvFiles.SelectedItems(0).ImageIndex = FolderImgIdx Then
      Exit Sub

  SaveDlg.FileName = lvFiles.SelectedItems(0).Text
  If SaveDlg.ShowDialog() <> DialogResult.OK Then Exit Sub
  DnldFile = lvFiles.SelectedItems(0).Text

  If FileCln.Download(AddSlash(txtFolder.Text) + _
             lvFiles.SelectedItems(0).Text, _
             ExtractFilePath(SaveDlg.FileName)) Then
    NowDownload = True
    txtDownload.Text = DnldFile + ": handshaking"
  Else
    CheckError(FileCln.LastError)
  End If
  UpdateStatus()
End Sub

The event OnDownloadProgress() informs about the download progress.

VB
'Download progress info
Private Sub FileCln_OnDownloadProgress(ByVal sender As Object, ByVal e As _
        AxbsFileClientSDK.IBSFileClnXEvents_OnDownloadProgressEvent) _
        Handles FileCln.OnDownloadProgress
  txtDownload.Text = DnldFile + " - " + _
           Str(e.aCountLo) + "/" + Str(e.aSizeLo)
End Sub

The event OnDownloadDone() is fired when the download is completed.

VB
'The download is completed
Private Sub FileCln_OnDownloadDone(ByVal sender As Object, _
        ByVal e As AxbsFileClientSDK.IBSFileClnXEvents_OnDownloadDoneEvent) _
        Handles FileCln.OnDownloadDone
  If e.aCode = 0 Then
    txtDownload.Text = DnldFile + " - Done."
  Else
    txtDownload.Text = DnldFile + " - Aborted: " + ErrorText(e.aCode)
  End If
  NowDownload = False
  Call UpdateButtons()
End Sub

Uploading a file

The method Upload() sends a request to upload a file.

VB
'Send upload request
Private Sub btnUpload_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnUpload.Click
  On Error GoTo IsCanceled

  OpenDlg.FileName = ""
  If OpenDlg.ShowDialog() <> DialogResult.OK Then Exit Sub

  UpldFile = OpenDlg.FileName
  If FileCln.Upload(UpldFile, txtFolder.Text) Then
    NowUpload = True
    UpldFol = txtFolder.Text
    txtUpload.Text = ExtractFileName(UpldFile) + ": handshaking"
  Else
    CheckError(FileCln.LastError)
  End If
  UpdateStatus()

IsCanceled:
End Sub

The event OnUploadProgress() provides information about the upload progress.

VB
'Upload progress info
Private Sub FileCln_OnUploadProgress(ByVal sender As Object, _
        ByVal e As AxbsFileClientSDK.IBSFileClnXEvents_OnUploadProgressEvent) _
        Handles FileCln.OnUploadProgress
  txtUpload.Text = ExtractFileName(UpldFile) + " - " + _
                   Str(e.aCountLo) + "/" + Str(e.aSizeLo)
End Sub

The event OnUploadDone() is fired when the upload operation is completed.

VB
'The upload is completed
Private Sub FileCln_OnUploadDone(ByVal sender As Object, _
        ByVal e As AxbsFileClientSDK.IBSFileClnXEvents_OnUploadDoneEvent) _
        Handles FileCln.OnUploadDone
  If e.aCode = 0 Then
    txtUpload.Text = ExtractFileName(UpldFile) + " - Done."
  Else
    txtUpload.Text = ExtractFileName(UpldFile) + _
                     " - Aborted: " + ErrorText(e.aCode)
  End If
  NowUpload = False
  Call UpdateButtons()
  If UpldFol = txtFolder.Text Then
    Call ListFolder()
  End If
End Sub

The bottom line

Nowadays, the Internet is insecure for a variety of reasons. Exchanging sensitive information could be a problem in many situations. In this article, we have presented one simple and affordable solution for secure private file sharing without the need of certificates.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here