System.ArgumentNullException error when attemtping to change string source from InputBox to an existing variable - vb.net

Summary
I am creating a VB project that requires a user to enter an API key. I do not want to store the API key in plaintext for security purposes, so I am attempting to encrypt it. When changing the source of the "password" from an InputBox to a earlier declared variable, I get an error of System.ArgumentNullException: 'String reference not set to an instance of a String. Parameter name: s', and the execution fails.
Context
For security reasons, I don't want the API key to be stored in Plaintext. Instead, I would like the user to enter it once during the application's initial launch, where it converts the plaintext API key into an encrypted file. To encrypt the file, I don't want the user to enter a password, instead, I have combined a few local variables (User name, MAC address, Install location and Host name.) to serve as a password instead. This means the user shouldn't need to enter it on launch (it will read the encrypted API key from the local file), but if any of the variables change (install location, local username, etc.) then it will error, and the user will need to re-enter the API key.
When I try to change the code from having to type in the password, to using the userKey variable, the program no longer launches correctly. Dim password As String = InputBox("Enter the password:") works fine, but Dim password As String = userKey leads to the above error, despite userKey being defined as a string, it refuses to accept it.
Outcome
I would like to have it so the user only needs to enter the API key once the application is first ever launched. It then takes the machine's data to essentially create a UUID, which is what is used to encrypt the plaintext API key entered by the user. I do not want the user to have to set or remember a password to decrypt the API key. It should be automated, and throw an error if they attempt to login where the automated data doesn't allow successful decryption. It'll wipe the API key and ask the user to re-enter it.
Currently, the code works, but the user has to enter their chosen password each time, which is what I am trying to avoid. I am wanting to fully automate this using the UUID I have generated as userKey which is generated when the form is loaded.
My Code
Please see the current code below. It should be in a working state, but I am unsure as to how I can have it so Dim password as String = userKey doesn't get an error when not having the user actualy typing it.
Conclusion
I am new to VB, so this is a new experiment for me to try and learn VB. Please be gentle - I'd appreciate any tips or tricks on how to best achieve this task and similar. Thanks!
Imports System.IO
Imports Newtonsoft.Json
Imports System.Security.Cryptography
Imports System.Net.NetworkInformation
Imports System.Management
Imports System.Text
Public Class Form1
Public userKey As String
Private posts As List(Of Post)
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim sHostName As String
Dim sUserName As String
Dim mac As String
Dim exePath As String = Application.ExecutablePath()
mac = getMacAddress()
' Get Host Name / Get Computer Name
sHostName = Environ$("computername")
' Get Current User Name
sUserName = Environ$("username")
Dim userKey As String
userKey = sUserName & mac & exePath & sHostName
Label5.Text = userKey
End Sub
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim plainText As String = InputBox("Enter the plain text:")
Dim password As String = InputBox("Enter the password:")
Dim wrapper As New Simple3Des(password)
Dim cipherText As String = wrapper.EncryptData(plainText)
MsgBox("The cipher text is: " & cipherText)
My.Computer.FileSystem.WriteAllText("cipherText.txt", cipherText, False)
End Sub
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim cipherText As String = My.Computer.FileSystem.ReadAllText("cipherText.txt")
Dim password As String = InputBox("Enter the password:")
Dim wrapper As New Simple3Des(password)
' DecryptData throws if the wrong password is used.
Try
Dim plainText As String = wrapper.DecryptData(cipherText)
MsgBox("The plain text is: " & plainText)
Catch ex As System.Security.Cryptography.CryptographicException
MsgBox("The data could not be decrypted with the password.")
End Try
End Sub
Function getMacAddress()
Dim nics() As NetworkInterface = NetworkInterface.GetAllNetworkInterfaces()
Return nics(1).GetPhysicalAddress.ToString
End Function
End Class
Public NotInheritable Class Simple3Des
Private TripleDes As New TripleDESCryptoServiceProvider
Private Function TruncateHash(
ByVal key As String,
ByVal length As Integer) As Byte()
Dim sha1 As New SHA1CryptoServiceProvider
' Hash the key.
Dim keyBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(key)
Dim hash() As Byte = sha1.ComputeHash(keyBytes)
' Truncate or pad the hash.
ReDim Preserve hash(length - 1)
Return hash
End Function
Sub New(ByVal key As String)
' Initialize the crypto provider.
TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8)
TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8)
End Sub
Public Function EncryptData(
ByVal plaintext As String) As String
' Convert the plaintext string to a byte array.
Dim plaintextBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(plaintext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the encoder to write to the stream.
Dim encStream As New CryptoStream(ms,
TripleDes.CreateEncryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
encStream.FlushFinalBlock()
' Convert the encrypted stream to a printable string.
Return Convert.ToBase64String(ms.ToArray)
End Function
Public Function DecryptData(
ByVal encryptedtext As String) As String
' Convert the encrypted text string to a byte array.
Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the decoder to write to the stream.
Dim decStream As New CryptoStream(ms,
TripleDes.CreateDecryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
decStream.Write(encryptedBytes, 0, encryptedBytes.Length)
decStream.FlushFinalBlock()
' Convert the plaintext stream to a string.
Return System.Text.Encoding.Unicode.GetString(ms.ToArray)
End Function
End Class

Related

To retreive sharepoint list data using client context

I am trying to retrieve Sharepoint list data using Microsoft.Sharepoint.Client library using vb.net windows form.
Below is the vb.net code for reference.
Imports Microsoft.SharePoint.Client
Public Class sharepoint_list
Private client_context As ClientContext
Private Sub sharepoint_list_Load(sender As Object, e As EventArgs) Handles MyBase.Load
client_context = New ClientContext("siteurl#user.com")
Dim web_ As Web = client_context.Web
client_context.Credentials = New SharePointOnlineCredentials("user#user.com", GetPassword("user#user.com", "mypass#123"))
client_context.Load(web_)
client_context.ExecuteQuery()
MsgBox(web_.Title)
End Sub
Public Function GetPassword(username As String, password As String) As Security.SecureString
Dim keyinfo As ConsoleKeyInfo
Dim securePass As Security.SecureString
securePass = New Security.SecureString
For Each c As Char In password
securePass.AppendChar(keyinfo.KeyChar)
Next
Return securePass
End Function
End Class
Whenever I try to run this piece of code, It throws an error with the following message
'.', hexadecimal value 0x00, is an invalid character.
and the following message on the console
A first chance exception of type 'System.ArgumentException' occurred
in System.Xml.dll
Any help would be appreciable.
Thanks in advance.
Modify the GetPassword method as below:
Public Function GetPassword(password As String) As Security.SecureString
Dim securePass As Security.SecureString
securePass = New Security.SecureString
For Each c As Char In password
securePass.AppendChar(c)
Next
Return securePass
End Function
Change the line of code below
client_context.Credentials = New SharePointOnlineCredentials("user#user.com", GetPassword("user#user.com", "mypass#123"))
to
client_context.Credentials = New SharePointOnlineCredentials("user#user.com", GetPassword("mypass#123"))

Escape invalid characters from text field

I have a login form that is used to process some database queries in VB. However, when tested on another PC with a username containing symbols such as '#', it falls over with no error.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Login.Click
Dim passStr As String = Password.Text
Dim userStr As String = Username.Text
...
I think it is due to invalid characters ruining the query, but am not sure how I can accept the login details, escaping them all.
I have found a way of removing them from the string but that is not very helpful when I need the login details to be valid!
Any way it is better to save password in an encrypted format. i will suggest you an encryption mechanism to store the password in an encrypted format. following is the function:
Imports System.Text.UnicodeEncoding
Dim uni As New UnicodeEncoding()
Public Function encodeUTF(ByVal inputString As String) As String '<-- function for encoding the input string
Dim byt() As Byte = uni.GetBytes(inputString)
encodeUTF = ""
For Each b As Byte In byt
encodeUTF &= b & ","
Next
Trim(Replace(encodeUTF, ",", ""))
End Function
hence your coding becomes:
Dim passStr As String = encodeUTF(Password.Text)
Dim userStr As String = encodeUTF(Username.Text)

Create Binary file of text that notepad can't read

I am attempting to create a binary file that is not readable by notepad in windows. This file needs to contain text information. The current code I run is readable in notepad (with a few extra characters here and there, but still human readable). Any assistance is greatly appreciated.
Using writer As BinaryWriter = New BinaryWriter(File.Open("file.bin", FileMode.Create))
writer.Write(rtbWriter.Text)
End Using
All files can be read by notepad - whether it is binary or not. If you don't want the text to be readable (or to be more accurate - understandable), consider using encryption.
EDIT: For an introduction on how to use encryption, see the link below to see how to use the 3DES cryptographic service provider in VB.NET:
simple encrypting / decrypting in VB.Net
*A more sophisticated approach would chain together the File Stream and Crypto Stream...
...but here's a very simple example showing how to encrypt/decrypt individual strings so you have something to play with and learn from:
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Public Class Form1
Private Key As String = "SomeRandomKeyThatIsHardCoded"
Private data As New List(Of String)
Private DataFileName As String = System.IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.MyDocuments, "SomeFile.txt")
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Some data to play with:
data.Add("User X, Access Y")
data.Add("User Y, Access Z")
data.Add("User Z, Access A")
ListBox1.DataSource = data
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' Write out each entry in encrypted form:
Using SW As New StreamWriter(DataFileName, False)
For Each entry As String In data
SW.WriteLine(Crypto.Encrypt(entry, Key))
Next
End Using
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
data.Clear()
ListBox1.DataSource = Nothing
' Read each encrypted line and decrypt it:
Using SR As New System.IO.StreamReader(DataFileName)
While Not SR.EndOfStream
data.Add(Crypto.Decrypt(SR.ReadLine, Key))
End While
End Using
ListBox1.DataSource = data
End Sub
End Class
Public Class Crypto
Private Shared DES As New TripleDESCryptoServiceProvider
Private Shared MD5 As New MD5CryptoServiceProvider
Public Shared Function MD5Hash(ByVal value As String) As Byte()
Return MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(value))
End Function
Public Shared Function Encrypt(ByVal stringToEncrypt As String, ByVal key As String) As String
DES.Key = Crypto.MD5Hash(key)
DES.Mode = CipherMode.ECB
Dim Buffer As Byte() = ASCIIEncoding.ASCII.GetBytes(stringToEncrypt)
Return Convert.ToBase64String(DES.CreateEncryptor().TransformFinalBlock(Buffer, 0, Buffer.Length))
End Function
Public Shared Function Decrypt(ByVal encryptedString As String, ByVal key As String) As String
Try
DES.Key = Crypto.MD5Hash(key)
DES.Mode = CipherMode.ECB
Dim Buffer As Byte() = Convert.FromBase64String(encryptedString)
Return ASCIIEncoding.ASCII.GetString(DES.CreateDecryptor().TransformFinalBlock(Buffer, 0, Buffer.Length))
Catch ex As Exception
Return ""
End Try
End Function
End Class

to save xml file in Vb.net

Public Function UploadCourseXML(ByVal fileStream As String, companyID As Integer, ByVal tokenID As String) As String Implements ICorePointService.UploadCourseXML
If (Not IsCustomerAuthentication(companyID, tokenID)) Then
Throw New Exception("Authentication failed. Please provider Company ID and Token ID")
End If
Dim doc As XDocument = XDocument.Parse(fileStream)
doc.Save("Update_XML")' error occures here... Access to the path c:\...etc. is denied
.. i want to save this in solution explorer
Return "result"
End Function
Refer this link :
http://support.microsoft.com/kb/301233
This for windows & web also
Imports System.IO
Imports System.Net
Imports System.Xml
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'To just download xml text
'Download text and save
Dim wc As New WebClient
Dim xmlText As String = wc.DownloadString("http://www.localcallingguide.com/xmllocalexch.php?exch=015800")
File.WriteAllText("new file path.xml", xmlText)
'Or
'To load stream directly into XML Document :
'Get data in stream
Dim webRequest As WebRequest = webRequest.Create("http://www.localcallingguide.com/xmllocalexch.php?exch=015800")
Dim webResponse As WebResponse = webRequest.GetResponse
Dim webStream As Stream = webResponse.GetResponseStream
'Optionally
'If you want you can read text from stream
'Dim reader As New StreamReader(webStream)
'reader.ReadToEnd 'will give same output as wc.downloadString()
'Load stream
Dim xmlDoc As New XmlDocument
xmlDoc.Load(webStream)
'select any level nodes using xpath
Dim Nodes As XmlNodeList = xmlDoc.SelectNodes("//lca-data/prefix/exch")
'iterate in selected nodes
For Each node As XmlNode In Nodes
RichTextBox1.AppendText(node.InnerText & vbCrLf)
Next
End Sub
End Class
You'll get a Access to the path '...' is denied error if the folder is flagged ReadOnly. You need to remove this flag prior to saving the file.
Dim info As DirectoryInfo = New DirectoryInfo("C:\folder1\folder2\folder3")
If (info.Exists AndAlso ((info.Attributes And FileAttributes.[ReadOnly]) = FileAttributes.[ReadOnly])) Then
info.Attributes = (info.Attributes Xor FileAttributes.[ReadOnly])
End If
If you're writing to an existing file, also make sure the file is not flagged ReadOnly. Just change DirectoryInfo to FileInfo.
Dim info As FileInfo = New FileInfo("C:\folder1\folder2\folder3\file.ext")
You may refer to the below given link to find out your problem,
http://support.microsoft.com/kb/2623670#method4

vb.net file.encrypt not supported workaround

Other threads have covered that file.encrypt on vb is not supported on W7HE. however i cant find a simple work around for it, and the only other function i know for encryption is using:
Imports system.security.Cryptography
and then doing along the lines of
Dim rsa As New RSACryptoServiceProvider
Dim encoder As New UTF8Encoding
etc,etc
however that only does strings, i need to encrypt the file as a whole.
Any ideas would be greatly appreciated
file.encrypt uses EFS, which is actually transparent encryption; the user account stores the master certificate, so anyone logged in under that account can access the file contents in any application. Depending on what you need, that might not be what you want at all. If you want to replicate EFS behavior for your app alone, it's as simple as storing a master password somewhere in the user's private files, split your data file into 'key' and 'data' sections, and encrypt the key with the master password. (Real EFS has some subtleties: It can encrypt the password separately for many different users, so it allows different users access per-file, giving a recovery option in case the main user's password is lost. It also uses the user's password to encrypt the master password, so if anyone changes the password they won't be able to open files.)
The basic method is just prompt the user for the password and use that to encrypt or decrypt the entire file at once rather than a string at a time. Serialize your file however you would unencrypted, then pass that whole byte array to something similar to EncryptStringToBytes_Aes. The one and only difference if you're writing bytes instead of a string is changing:
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
to
csEncrypt.Write(plainText);
Either way, for the actual crypto you'd use AesCryptoServiceProvider, not RSACryptoServiceProvider, which is for the top-level authentication and encryption of keys/passwords that get passed to AES and similar algorithms. It's rarely used to encrypt whole files, and is dreadfully slow when you do.
I'm enclosing a program I wrote to help you along the way. It is very effective and will encrypt whatever you want. I left notes in it to answer all your questions. At the bottom, you will see an added class to reduce memory usage of the program. It works rather well, (by 8% -10%) Enjoy. Items needed: *3 buttons (Browse) (Encrypt) (Decrypt) *1 TextBox For the project video, see my link:
Part 1: https://www.youtube.com/watch?v=sVaA2q8ttzQ
Part 2: https://www.youtube.com/watch?v=TyafeBJ53YU
'Created by: Rythorian77 | github.com/rythorian77
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ramClass As New AESRam()
End Sub
Private Sub Browse_Click(sender As Object, e As EventArgs) Handles Browse.Click
'Allows you to access files from folders
Dim fetchCryptDialog As New OpenFileDialog With {
.CheckFileExists = True,
.InitialDirectory = "C:\",
.Multiselect = False
}
If fetchCryptDialog.ShowDialog = DialogResult.OK Then
TextBox1.Text = fetchCryptDialog.FileName
End If
End Sub
Private Sub Encrypt_Click(sender As Object, e As EventArgs) Handles Encrypt.Click
'File path goes to textbox
Dim Rythorian77 As String = TextBox1.Text
'This password can be whater you want.
Dim password As String = "123456789ABCDEFG!##$%^&*()_+"
'A data type is the characteristic of a variable that determines what kind of data it can hold.
'Data types include those in the following table as well as user-defined types and specific types of objects.
Dim key As Byte() = New Byte(31) {}
'When overridden in a derived class, encodes a set of characters into a sequence of bytes.
Encoding.Default.GetBytes(password).CopyTo(key, 0)
'RijndaelManaged still works but is considered obsolete in todays world so we use AES
'Represents the abstract base class from which all implementations of the Advanced Encryption Standard (AES) must inherit.
'https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-6.0
Dim aes As New RijndaelManaged() With
{
.Mode = CipherMode.CBC,
.KeySize = 256,
.BlockSize = 256,
.Padding = PaddingMode.Zeros
}
'Reads a sequence of bytes from the current memory stream and advances the position within the memory stream by the number of bytes read.
Using mnemonicData As New MemoryStream
'Defines a stream that links data streams to cryptographic transformations.
Using cStream As New CryptoStream(mnemonicData, aes.CreateEncryptor(key, key), CryptoStreamMode.Write)
Dim buffer As Byte() = File.ReadAllBytes(Rythorian77)
cStream.Write(buffer, 0, buffer.Length)
Dim appendBuffer As Byte() = mnemonicData.ToArray()
Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
appendBuffer.CopyTo(finalBuffer, 0)
File.WriteAllBytes(Rythorian77, finalBuffer)
End Using
End Using
End Sub
'The above code notes compliment the same
Private Sub Decrypt_Click(sender As Object, e As EventArgs) Handles Decrypt.Click
Dim Rythorian77 As String = TextBox1.Text
Dim password As String = "123456789ABCDEFG!##$%^&*()_+"
Dim key As Byte() = New Byte(31) {}
Encoding.Default.GetBytes(password).CopyTo(key, 0)
Dim aes As New RijndaelManaged() With
{
.Mode = CipherMode.CBC,
.KeySize = 256,
.BlockSize = 256,
.Padding = PaddingMode.Zeros
}
Using mnemonicData As New MemoryStream
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> < aes.CreateDecryptor > is the only change from above aes.CreateEncryptor
Using cStream As New CryptoStream(mnemonicData, aes.CreateDecryptor(key, key), CryptoStreamMode.Write)
Dim buffer As Byte() = File.ReadAllBytes(Rythorian77)
cStream.Write(buffer, 0, buffer.Length)
Dim appendBuffer As Byte() = mnemonicData.ToArray()
Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
appendBuffer.CopyTo(finalBuffer, 0)
File.WriteAllBytes(Rythorian77, finalBuffer)
End Using
End Using
End Sub
End Class
**Add this separate Class:**
Imports System.Runtime.InteropServices
Public Class AESRam
'This controls the amount of RAM that your process uses, it doesn't otherwise have any affect on the virtual memory size of your process.
'Sets the minimum and maximum working set sizes for the specified process.
'This will cut memory usage in half.
<DllImport("KERNEL32.DLL", EntryPoint:="SetProcessWorkingSetSize", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)>
Friend Shared Function SetProcessWorkingSetSize(pProcess As IntPtr, dwMinimumWorkingSetSize As Integer, dwMaximumWorkingSetSize As Integer) As Boolean
End Function
'Retrieves a pseudo handle for the current process.
<DllImport("KERNEL32.DLL", EntryPoint:="GetCurrentProcess", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)>
Friend Shared Function GetCurrentProcess() As IntPtr
End Function
'See Above
Public Sub New()
Dim pHandle As IntPtr = GetCurrentProcess()
SetProcessWorkingSetSize(pHandle, -1, -1)
End Sub
End Class