Simple Reversible Encryption for VBScripts

Lee W, MVPTechnology and Business Process Advisor
CERTIFIED EXPERT
Jack of All Trades with an interest in facilitating networking through social interaction of IT Professionals
Published:
Updated:
Leaving sensitive information (like passwords) in clear text scripts is never a good practice, though it's sometimes unavoidable.  This set of VBScript functions can be used to obscure critical information making it at least a little more difficult for curious eyes (or worse) to see.

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:

  • The ASCII value of the character
  • An increment amount that is multiplied by the maximum number of salt characters
  • The maximum number of salt characters.


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.


  • Some organizations may employ tools that search and index the content of files on your network.  Where possible, these tools may read the content of the scripts (f you implement these tools, you may be able to configure them to exclude certain file types - if you don't, you are relying on someone else to properly configure them).  Since you don't want your passwords searchable on your network, using this level of encryption can prevent that.
  • By using this method (or a similar method), you can safely demonstrate scripts without exposing the password to others.
  • For IT consultants in small organizations, you might have scripts utilized by your users but as clear text files, they can open them and see passwords you may have stored.  For the non-technical (or not too technical) user, this method may be sufficient security to prevent them obtaining sensitive credentials.


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.

1
7,474 Views
Lee W, MVPTechnology and Business Process Advisor
CERTIFIED EXPERT
Jack of All Trades with an interest in facilitating networking through social interaction of IT Professionals

Comments (5)

Lee W, MVPTechnology and Business Process Advisor
CERTIFIED EXPERT
Most Valuable Expert 2013

Author

Commented:
If you're still having issues, run the hash through the decode from the script that created it.  Or post a screen shot.
RobOwner (Aidellio)
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
Hi Lee,

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:
C:\Users\rjurd\OneDrive\Desktop>encrypt.vbs E monsterAiden18 10-10-10
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

674A748B36662E6DB5860512A66C8698F6E0B910238EF143C1E206F731E7AAAC23757697449AB80B982D89F89DBE77B73B22B555A67FAA4B9EE634B30F6A

C:\Users\rjurd\OneDrive\Desktop>encrypt.vbs D 674A748B36662E6DB5860512A66C8698F6E0B910238EF143C1E206F731E7AAAC23757697449AB80B982D89F89DBE77B73B22B555A67FAA4B9EE634B30F6A 10-10-10
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

C:\Users\rjurd\OneDrive\Desktop\encrypt.vbs(43, 9) Microsoft VBScript runtime error: Invalid procedure call or argument: 'Chr'

Open in new window

Lee W, MVPTechnology and Business Process Advisor
CERTIFIED EXPERT
Most Valuable Expert 2013

Author

Commented:
@Rob, I'm glad you find it useful!  Thanks to your comment I realized I forgot to mention a key point (no pun intended).  The last digit cannot be greater than 9.  I've also detailed how the hashes are made up, hopefully a little more clearly than following the code.  This is by design.

@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).
Lee W, MVPTechnology and Business Process Advisor
CERTIFIED EXPERT
Most Valuable Expert 2013

Author

Commented:
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
Things that need elevation will not work that way unless UAC is off, or you use the built-in administrator, Lee, because for that account, UAC is off.  I wouldn't recommend to use it for this purpose for another reason: startup scripts or immediate tasks do the same much easier.

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.