It seems these days I’m writing a lot of VBScript scripts. My scripts are often interacting with a MySQL database but could be doing other things as well, such as connecting to workstations to push files. One of the biggest problems with scripts that need credentials is how to store the password in these clear text files. I’ve come up with a reversible encryption to store the password. The script below allows you to completely encrypt or decrypt a password using a custom key.
Now I fancy myself as security aware – I am not an IT Security professional. And this script is not intended as a truly secure method of storing passwords. Nor am I suggesting it is unbreakable or otherwise hard to decode without the key and encryption methodology below. It is ONLY meant to OBSCURE otherwise clear-text passwords in VBScripts. And obscurity is not security. Clear?
On to the script…
Option Explicit
Function GetParam(ParamNumber) 'Exclusive to VBS Scripts
Dim GetParam_CmdArgs
Set GetParam_CmdArgs = WScript.Arguments
If GetParam_CmdArgs.Count = 3 Then
GetParam = GetParam_CmdArgs(ParamNumber)
ElseIf GetParam_CmdArgs.Count = 1 Then
If UCase(Left(GetParam_CmdArgs(0), 1)) = "H" Then Help
End If
End Function
Function ValidKey(Key) 'Ensures constants when computing character hexadecimal values don't exceed 255 (FF)
Dim ValidKey_KeyParams
ValidKey_KeyParams = Split(Key, "-") 'Using "-" as a delimiter makes it impossible to have a negative number
If UBound(ValidKey_KeyParams) <> 2 Then 'Wrong number of parameters in key
ValidKey = False
Else 'Max computed value is 127.
If ValidKey_KeyParams(0) + (ValidKey_KeyParams(1) * ValidKey_KeyParams(2)) > 127 Then
ValidKey = False
Else
ValidKey = True
End If
End If
End Function
Function DecryptPassword(UseHash, Key)
Dim DecryptPassword_KeyParams
Dim DecryptPassword_PWChar
Dim DecryptPassword_ChkChar
Dim DecryptPassword_UseString
Dim DecryptPassword_Count
DecryptPassword_KeyParams = Split(Key, "-")
DecryptPassword_UseString = UseHash
DecryptPassword_Count = 0
Do Until Len(DecryptPassword_UseString) < 3 '3 is minimum length of a character Char 1 = Salt 0, Char 2, 3 = Hex of Ascii code
DecryptPassword_ChkChar = CInt(Left(DecryptPassword_UseString, 1)) 'Start with the first character of the current version of the password string
DecryptPassword_PWChar = (CInt(Clng("&h" & Mid(DecryptPassword_UseString, DecryptPassword_ChkChar + 2, 2)) - (DecryptPassword_KeyParams(0) + DecryptPassword_KeyParams(1) * DecryptPassword_ChkChar)))
DecryptPassword = DecryptPassword & Chr(DecryptPassword_PWChar)
DecryptPassword_UseString = Trim(Right(DecryptPassword_UseString, Len(DecryptPassword_UseString) - DecryptPassword_ChkChar - 3))
Loop
End Function
Function RandomChar 'Generate a random hexadecimal value
Randomize Timer
RandomChar = Trim(Hex(Int(Rnd * 16)))
End Function
Function EncryptPassword(UsePassword, Key)
Dim EncryptPassword_Character
Dim EncryptPassword_SaltChars
Dim EncryptPassword_KeyParams
Dim EncryptPassword_Salt
If ValidKey(Key) = False Then
WScript.Echo "The key provided is not valid."
WScript.Echo ""
Help
End If
EncryptPassword_KeyParams = Split(Key, "-")
Randomize Timer
If Len(UsePassword) > 0 Then
For EncryptPassword_Character = 1 To Len(UsePassword)
EncryptPassword_SaltChars = Int(Rnd * (EncryptPassword_KeyParams(2) + 1))
EncryptPassword = EncryptPassword & EncryptPassword_SaltChars
For EncryptPassword_Salt = 1 To EncryptPassword_SaltChars
EncryptPassword = EncryptPassword & RandomChar
Next
EncryptPassword = EncryptPassword & Hex(Asc(Mid(UsePassword, EncryptPassword_Character, 1)) + (EncryptPassword_KeyParams(0) + EncryptPassword_SaltChars * EncryptPassword_KeyParams(1)))
Next
End If
If Len(EncryptPassword) Mod 2 = 1 Then EncryptPassword = EncryptPassword & RandomChar 'Ensures hash value is always even
End Function
Sub Main 'The glue to the above functions; While it may exist on other platforms, code likely differs greatly.
If UCase(Left(GetParam(0), 1)) = "E" Then
WScript.Echo EncryptPassword(GetParam(1), GetParam(2))
ElseIf UCase(Left(GetParam(0), 1)) = "D" Then
WScript.Echo DecryptPassword(GetParam(1), GetParam(2))
ElseIf UCase(Left(GetParam(0), 1)) = "H" Then
Help
Else
WScript.Echo "Bad parameters"
End If
End Sub
Sub Help 'Exclusive to VBS Scripts
WScript.Echo ""
WScript.Echo "Usage:"
WScript.Echo " " & WScript.ScriptName & " Encrypt Password Key"
WScript.Echo " " & WScript.ScriptName & " Decrypt PasswordHash Key"
WScript.Echo ""
WSCript.Echo "Example:"
WScript.Echo " " & WScript.ScriptName & " Encrypt ThisIsMyPassword 10-6-5"
WScript.Echo " " & WScript.ScriptName & " Decrypt 08C07D32FCA413962EAA13E5995D 10-6-5"
WScript.Echo ""
WScript.Echo " Parameter 1 identifies the action. Only the first letter is"
WScript.Echo " evaluated. Not case sensitive."
WScript.Echo " Parameter 2 identifies the password to encode or hash to"
WScript.Echo " decode. Passwords are case sensitive, hashes are not."
WScript.Echo " Parameter 3 identifies the key. See below."
WScript.Echo ""
WScript.Echo "Notes: "
WScript.Echo " The value of the first number + (second number * third number)"
WScript.Echo " cannot exceed 127. A key of 60-9-5 = 105 and is valid. A key of"
WScript.Echo " 50-9-9 = 131 and would not be valid. Dashes (-) must be used."
WScript.Echo ""
WScript.Echo " The maximum value of the last digit in the key is 9."
WScript.Echo ""
WScript.Quit
End Sub
Main 'Execute the script.
First, you’ll need the complete script so that you can encode a password, creating the hash. The hash is then used in place of your password in the script. Save the above code to a .vbs file name of your choosing. In the screen shot below, I've saved it to ObscurePW.vbs to create a hash for a sample password of "SamplePassword1"
When using with your own scripts, you just need to copy the decrypt function into your own script.
Here's a sample script that maps a network drive to \\computer1\share1 specifying the user and password to use when connecting:
Dim Network
Set Network = WScript.CreateObject("WScript.Network")
UserNameVariable = "administrator"
PasswordVariable = "SamplePassword1"
Network.MapNetworkDrive "Z:", "\\computer1\share1", "false", UserNameVariable, PasswordVariable
As anyone can see, the password is "SamplePassword1". So if we modified the script by adding the DecryptPassword function, we could then set the password to the hash above and instead of referencing the PasswordVariable, we reference Decrypt(PasswordVariable, "12-5-7"). Now this is what the code looks like:
Function DecryptPassword(UseHash, Key)
Dim DecryptPassword_KeyParams
Dim DecryptPassword_PWChar
Dim DecryptPassword_ChkChar
Dim DecryptPassword_UseString
Dim DecryptPassword_Count
DecryptPassword_KeyParams = Split(Key, "-")
DecryptPassword_UseString = UseHash
DecryptPassword_Count = 0
Do Until Len(DecryptPassword_UseString) < 3 '3 is minimum length of a character Char 1 = Salt 0, Char 2, 3 = Hex of Ascii code
DecryptPassword_ChkChar = CInt(Left(DecryptPassword_UseString, 1))'Start with the first character of the current version of the password string
DecryptPassword_PWChar = (CInt(Clng("&h" & Mid(DecryptPassword_UseString, DecryptPassword_ChkChar + 2, 2)) - (DecryptPassword_KeyParams(0) + DecryptPassword_KeyParams(1) * DecryptPassword_ChkChar)))
DecryptPassword = DecryptPassword & Chr(DecryptPassword_PWChar)
DecryptPassword_UseString = Trim(Right(DecryptPassword_UseString, Len(DecryptPassword_UseString) - DecryptPassword_ChkChar - 3))
Loop
End Function
Dim Network
Set Network = WScript.CreateObject("WScript.Network")
UserNameVariable = "administrator"
PasswordVariable = "2406964158338B7B3AE2D29C6F733169A4C3BC8C5F04BB8A31096B53A0EB8637778E07F118807B511678972D27A1A425"
Network.MapNetworkDrive "Z:", "\\computer1\share1", "false", UserName, DecryptPassword(PasswordVariable, "12-5-7")
Note: if you're planning on testing the above sample script, don't use as administrative share to do so. Restrictions in place through UAC can prevent even local administrator accounts from accessing the admin shares. For more information, see https://helgeklein.com/blog/2011/08/access-denied-trying-to-connect-to-administrative-shares-on-windows-7/
The Key
To encrypt, the function uses three things:
With a key of 12-5-7 we are taking the ASCII value of the character and adding 12 to it. Then we're also adding 35 to it (5x7). Finally we're adding UP TO 7 salt digits to the hash - this is randomly determined and why the hash can vary in length each time you encrypt - as well as why the hash can vary in appearance.
When we store the value to decode, the first digit is the number of salt characters (therefore, the number of salt characters cannot be greater than 9 or it would take two digits (or I'd have to modify the code to accept hexadecimal numbers)). So when a hash starts with 3, the next three digits are, in essence, garbage, and ignored. Then the next two digits (digits 5 and 6) are the ASCII value of the character + (using the 12-5-7 key) 47.
Because non-special characters are all under ASCII 128, the maximum value the key can create without forcing a 3rd hexadecimal digit when creating the hash is 127 - which is why a key like 50-9-9 would fail (50+(9x9)) = 131.
Like I said, this is not fool proof encryption. If you know how to read it - or have access to the decryption function, it's very easy to crack. But for every day prying eyes, it should do the job nicely.
Usage Scenarios
This is considered reversible encryption meaning that you can decrypt it easily enough. If you're more of a programmer than I, you may be able to exploit better third party technologies like PGP. If you're not, or you don't have more than a basic need for security, this may be sufficient for you.
Again, this is NOT intended to secure highly sensitive information such as your bank account passwords, your domain admin credentials (in most cases), your bitcoin wallet, or your passwords to your private email. And I wouldn't recommend storing other people's passwords with this level of encryption.
That said, if anyone wants to IGNORE the decrypt/encrypt routines and has some kind of password cracking tool, I would encourage you to attempt to crack the password - just let me know you did it, with what tools, what password, and how long it took you.
About the Script
I encourage you to review the code, see what I'm doing and if VBScript is not a strength, hopefully, you can pick up something new from it. Some of the things I'm doing to make this RELATIVELY secure is salting each and every character in the password with a random number of salt characters. This means that each time you run the encrypt function, you will get a different value, and likely, a different length. Without the DecryptPassword function, your average IT admin or script kiddie is not likely to be able to decode this. But, OBVIOUSLY, to make this work, the DecryptPassword function is embedded in the code. Still, it will take at least a LITTLE effort for someone to obtain the actual password.
Important Note: The above script is designed to be executed from the command line using the CSCRIPT.EXE VBScript processor. The WSCRIPT.EXE VBScript processor is the default and will attempt to run things graphically. Since this script requires command line input (the action, password/hash, and key), it is not practical to run it through a simple double-click or the WSCRIPT.EXE processor. You must run it from the command line.
Other Uses
While this script was written and tested as a VBScript, the Encrypt and Decrypt functions should work with little to no modification on other VB platforms, such as VB6, ASP, and VBA.
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (5)
Author
Commented:Commented:
I really like this script as I've had to use a lot of vbs for automating systems and interacting with databases and reports and this would be really useful.
I did get an error with the Decrypt part when using a 10-10-10 key. Is there a limitation to the size of the key? what am I missing? The following did work when I used a smaller key e.g. 7-7-7
Error:
Open in new window
Author
Commented:@everyone else, if you have a problem like Rob did, please let me know. I'd like to perfect this as much as I can perfect it. I'm also open to tips to make it stronger (already have one idea).
Author
Commented:https://www.experts-exchange.com/questions/22502969/How-to-run-VBScript-as-an-administrator.html
Commented: