Giter Club home page Giter Club logo

aes.vbs's Introduction

AES-256-CBC in VBScript

This project provides VBScript functions to perform encryption and decryption with AES-256-CBC.

View Source MIT License

While performing encryption/decryption, it also computes/verifies a message authentication code (MAC) using HMAC-SHA-256 to maintain integrity and authenticity of initialization vector (IV) and ciphertext.

Note: This project does not implement the cryptographic primitives from scratch. It is a wrapper around Microsoft's Common Object Runtime Library (mscorlib.dll).

Contents

Features

Here are some of the features of this project:

  • Works with Base64 encoded keys.

  • Exposes two simple functions named Encrypt() and Decrypt() that perform AES-256-CBC encryption and decryption along with computing and verifying MAC using HMAC-SHA-256 to ensure integrity and authenticity of IV and ciphertext.

  • Initialization vector (IV) is automatically generated. Caller does not need to worry about it.

  • Message authentication code (MAC) is computed by Encrypt() and verified by Decrypt() to ensure the integrity and authenticity of IV and ciphertext. HMAC-SHA-256 is used to generate MAC.

  • Encrypt() returns the MAC, IV, and ciphertext concatenated together as a single string which can then be fed directly to Decrypt(). The three fields are joined by colons in the concatenated string. No need to worry about maintaining the MAC and IV yourself.

  • Can be used with Classic ASP. Just put the entire source code within the ASP <% and %> delimiters in a file named aes.inc and include it in ASP files with an #include directive like this:

    <!-- #include file="aes.inc" -->

Note: This is not a crypto library. You can use it like one if all you want to use is AES-256-CBC with HMAC-SHA-256. It does not support anything else. If you want a different key size, cipher mode, or MAC algorithm, you'll have to dive into the source code and modify it as per your needs. If you do so, you might find one or more of the documentation links provided in the References section useful.

Why?

Why not?

Okay, the real story behind writing this project involved a legacy application written in Classic ASP and VBScript. It used an outdated cipher that needed to be updated. That's what prompted me to create a wrapper for AES-256-CBC with HMAC-SHA-256 in VBScript. After writing it, I thought it would be good to share it on the Internet in case someone else is looking for something like this.

Demo Script

On a Windows system, enter the following command to see a quick demo:

cscript aesdemo.wsf

The Windows Script File (WSF) named aesdemo.wsf loads aes.vbs and executes the functions defined in it.

Demo Output

The output from the demo script looks like this:

demoAESKey: CKkPfmeHzhuGf2WYY2CIo5C6aGCyM5JR8gTaaI0IRJg=
demoMACKey: wDF4W9XQ6wy2DmI/7+ONF+mwCEr9tVgWGLGHUYnguh4=
encrypted1: Ru7CEo3KJBMT9ati55ASO0xJOVw5+7crhL4RxQSVu1s=:dHTHWCy5sGu9z7gUAa0tpA==:sBbmFDtzkPU7kD4T1OSbvw==
decrypted1: hello
encrypted2: 7BnQ5trOLDk8cecEnVayfSW9Q2fA38FvFkDlwHxbAKA=:M1ipFnh884qcXYlX9NPjwA==:ANF8P0PfaUQwvcS2jiIpdQ==
decrypted2: hello

aes.BlockSize: 128
aes.FeedbackSize: 128
aes.KeySize: 256
aes.Mode: 1
aes.Padding: 2
mac.HashName: SHA256
mac.HashSize: 256
aesEnc.InputBlockSize: 16
aesEnc.OutputBlockSize: 16
aesDec.InputBlockSize: 16
aesDec.OutputBlockSize: 16
b64Enc.InputBlockSize: 3
b64Enc.OutputBlockSize: 4
b64Dec.InputBlockSize: 1
b64Dec.OutputBlockSize: 3

Only the third line of output (encrypted1) changes on every run because it depends on a dynamically generated initialization vector (IV) which is different each time it is generated. This is, in fact, an important security requirement for achieving semantic security.

For example, if a database contains encrypted secrets from various users and if the same plaintext always encrypts to the same ciphertext (which would happen if the key and IV remain constant between encryptions), then we can tell that two users have the same plaintext secrets if their ciphertexts are equal in the database. Being able to do so violates the requirements of semantic security which requires that an adversary must not be able to compute any information about a plaintext from its ciphertext. This is why the ciphertext needs to be different for the same plaintext in different encryptions and this is why we need a random IV for each encryption.

There are two blocks of output shown above. The first block shows example keys and ciphertexts along with the plaintexts they decrypt to. The second block shows the default properties of the cryptography objects used in the VBScript code. Both blocks of output are explained in detail in the sections below.

Example Ciphertexts

The first block of output in the demo script looks like this:

demoAESKey: CKkPfmeHzhuGf2WYY2CIo5C6aGCyM5JR8gTaaI0IRJg=
demoMACKey: wDF4W9XQ6wy2DmI/7+ONF+mwCEr9tVgWGLGHUYnguh4=
encrypted1: Ru7CEo3KJBMT9ati55ASO0xJOVw5+7crhL4RxQSVu1s=:dHTHWCy5sGu9z7gUAa0tpA==:sBbmFDtzkPU7kD4T1OSbvw==
decrypted1: hello
encrypted2: 7BnQ5trOLDk8cecEnVayfSW9Q2fA38FvFkDlwHxbAKA=:M1ipFnh884qcXYlX9NPjwA==:ANF8P0PfaUQwvcS2jiIpdQ==
decrypted2: hello

The third line of output (encrypted1) changes on every run because it depends on a dynamically generated initialization vector (IV) used in the encryption. The fifth line of output (encrypted2) remains the same because it is hardcoded in the demo script.

Each encrypted value in the output is actually a concatenation of the message authentication code (MAC), colon (:), initialization vector (IV), colon (:), and ciphertext.

The ciphertext is generated with a function call like this:

demoPlaintext = "hello"
demoAESKey = "CKkPfmeHzhuGf2WYY2CIo5C6aGCyM5JR8gTaaI0IRJg="
demoMACKey = "wDF4W9XQ6wy2DmI/7+ONF+mwCEr9tVgWGLGHUYnguh4="
encrypted1 = Encrypt(demoPlaintext, demoAESKey, demoMACKey)

The encrypted value (i.e., concatenated MAC, colon, IV, colon, and ciphertext) can be decrypted back to plaintext with a function call like this:

decrypted1 = Decrypt(encrypted1, demoAESKey, demoMACKey)

The Encrypt and Decrypt functions are defined in aes.vbs.

Crypto Properties

The second block of output from the demo script looks like this:

aes.BlockSize: 128
aes.FeedbackSize: 128
aes.KeySize: 256
aes.Mode: 1
aes.Padding: 2
mac.HashName: SHA256
mac.HashSize: 256
aesEnc.InputBlockSize: 16
aesEnc.OutputBlockSize: 16
aesDec.InputBlockSize: 16
aesDec.OutputBlockSize: 16
b64Enc.InputBlockSize: 3
b64Enc.OutputBlockSize: 4
b64Dec.InputBlockSize: 1
b64Dec.OutputBlockSize: 3

These are the values of the properties of various cryptography objects used in aes.vbs. The output shows the following details:

  • The aes object (of class RijndaelManaged) has a default key size of 256 bits.
  • The block size is 128 bits. The mode is 1, i.e., CBC. See RijndaelManaged.Mode and CipherMode documentation to confirm that the default mode is indeed CBC.
  • The padding mode is 2, i.e., PKCS #7. See RijndaelManaged.Padding and PaddingMode documentation to confirm that the default padding mode is indeed PKCS #7.

We do not change these defaults in aes.vbs and we supply a 256-bit encryption key to Encrypt and Decrypt functions to ensure that we use AES-256-CBC for encryption.

OpenSSL CLI Examples

For troubleshooting purpose, there are two shell scripts named encrypt and decrypt present in the current directory. Here is the synopsis of these scripts:

plaintext=PLAINTEXT aes_key=AES_KEY aes_iv=AES_IV mac_key=MAC_KEY sh encrypt
ciphertext=CIPHERTEXT aes_key=AES_KEY mac_key=MAC_KEY sh decrypt

These scripts are merely wrappers around OpenSSL. They accept Base64 key and Base64 IV and convert them to hexadecimal for OpenSSL command line tool to consume.

To see example usage of the script we will use these three values from the demo output:

demoAESKey: CKkPfmeHzhuGf2WYY2CIo5C6aGCyM5JR8gTaaI0IRJg=
demoMACKey: wDF4W9XQ6wy2DmI/7+ONF+mwCEr9tVgWGLGHUYnguh4=
encrypted2: 7BnQ5trOLDk8cecEnVayfSW9Q2fA38FvFkDlwHxbAKA=:M1ipFnh884qcXYlX9NPjwA==:ANF8P0PfaUQwvcS2jiIpdQ==
decrypted2: hello

Here is how to use the encrypt and decrypt scripts:

  1. Encrypt the plaintext hello with the demo AES key and IV, and compute MAC of the result with the demo MAC key:

    plaintext=hello \
    aes_key=CKkPfmeHzhuGf2WYY2CIo5C6aGCyM5JR8gTaaI0IRJg= \
    aes_iv=M1ipFnh884qcXYlX9NPjwA== \
    mac_key=wDF4W9XQ6wy2DmI/7+ONF+mwCEr9tVgWGLGHUYnguh4= \
    sh encrypt

    The output should match the string in the encrypted2 value.

  2. Verify MAC and decrypt the ciphertext to obtain the plaintext AES keys and IV.

    ciphertext=7BnQ5trOLDk8cecEnVayfSW9Q2fA38FvFkDlwHxbAKA=:M1ipFnh884qcXYlX9NPjwA==:ANF8P0PfaUQwvcS2jiIpdQ== \
    aes_key=CKkPfmeHzhuGf2WYY2CIo5C6aGCyM5JR8gTaaI0IRJg= \
    mac_key=wDF4W9XQ6wy2DmI/7+ONF+mwCEr9tVgWGLGHUYnguh4= \
    sh decrypt

    The output should match the plaintext in the decrypted2 value.

Questions and Answers

  1. Can we not use AesManaged instead of RijndaelManaged in aes.vbs?

    No, we cannot use AesManaged in VBScript. We can use only those classes that are defined in mscorlib.dll. RijndaelManaged exists in mscorlib.dll but AesManaged does not.

    As a result, we get an error for this VBScript code:

    Set aes = CreateObject("System.Security.Cryptography.AesManaged")

    Here is the error that occurs:

    ActiveX component can't create object: 'System.Security.Cryptography.AesManaged'
    

    Here is a command that shows the DLLs in which the two classes are present:

    C:\>powershell -Command [System.Reflection.Assembly]::GetAssembly('System.Security.Cryptography.RijndaelManaged')
    
    GAC    Version        Location
    ---    -------        --------
    True   v4.0.30319     C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll
    
    C:\>powershell -Command [System.Reflection.Assembly]::GetAssembly('System.Security.Cryptography.AesManaged')
    
    GAC    Version        Location
    ---    -------        --------
    True   v4.0.30319     C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll

    This is why we use RijndaelManaged in our VBScript code.

  2. Is RijndaelManaged suitable as AES cipher?

    Yes, it is.

    The RijndaelManaged class allows setting its KeySize and BlockSize properties independently to 128, 160, 192, 224, or 256. Further, the key size need not match the block size.

    But the AesManaged class allows setting its KeySize to 128, 192, or 256 only. The BlockSize property must be 128 only. These constraints match the key sizes and the block size defined in the AES standard (see section 5 of FIPS 197).

    Therefore, AesManaged class is the preferred class to use because it is not possible to use it in a non-conformant manner. But since this class cannot be used in VBScript as explained in the previous point and since we stick to the default key size of 256 bits and the default block size of 128 bits while using RijndaelManaged as explained in section Crypto Properties, it is a suitable substitute for AesManaged.

    Further, the section OpenSSL CLI examples shows that the default properties of this cipher is compatible with openssl aes-256-cbc.

  3. Instead of using a Base64 encoded 256-bit key, can we not use a password and derive a 256-bit key from it using a key derivative function (KDF)?

    This is not easily possible in VBScript because there are only two key derivative functions available in mscorlib.dll:

    However, they are not registered in Windows registry by default. Therefore, like AesManaged class, these two classes too cannot be used in VBScript code without modifying the registry.

    If we consider brute-force search of the key, then in case of a key derived from a password using a KDF, an attacker could either search the password which would be inefficient due to the use of KDF or an attacker could search the encryption key directly. Brute-force search of the key can be slower than brute-search of the password if the password is small and small number of iterations is used in the KDF. Therefore, using a 256-bit key directly is never worse than using a key derived from a password.

References

License

This is free and open source software. You can use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of it, under the terms of the MIT License. See LICENSE.md for details.

This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or implied. See LICENSE.md for details.

Support

To report bugs, suggest improvements, or ask questions, please create a new issue at http://github.com/susam/aes.vbs/issues.

aes.vbs's People

Contributors

susam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

aes.vbs's Issues

Excel - how implement as formulas?

Hello.

How use aes.vbs to create Excel formulas?

General I have HEX 128 bits AES CBC data like this:

063195FB35FD19DAC4C6DCD4ED773A36

the key is (also in HEX, general is deferential but in my example use zeros only) :

00000000000000000000000000000000

result is

2E026256917E06C38D6FAB8F92A0A028

Understood that in Excel press ALT+F11 (dev window), insert new module, paste code but what next? Sorry, I'm not a developer, something know but rather I'm end user that need decode thousands values like about data. Can someone help please.

BR, Krzysiek

the script is not working in WinPE

Hello,
thanks for the great script but I tried it in WinPE and it's not working, it failed at the first line and gave error, please advise
Set utf8 = CreateObject("System.Text.UTF8Encoding")

Modified code for AES ECB

Hi, very impressed with your code package and i was looking for AES in ECB mode, because the end system i connect is using 128 - ECB AES algorithm to decrypt, so i should encrypt with same. I have end up with below code and i would like to have "text to encrypt" and "key" as parameter, no IV or no MAC required.

I am expecting something like this

Set utf8 = CreateObject("System.Text.UTF8Encoding")
aesKeyBytes = B64Decode(aesKey)
Set aesEnc = AES.CreateEncryptor_2((aesKeyBytes)) ' without IV - but not sure about the syntax
plainBytes = utf8.GetBytes_4(plaintext)
cipherBytes = aesEnc .TransformFinalBlock((plainBytes), 0, UBound(plainBytes))
Encrypt = B64Encode(cipherBytes)

Complete code:

Function Min(a, b)
    Min = a
    If b < a Then Min = b
End Function

Function B64Encode(bytes)
    Dim result As String
    Dim b64Block() As Byte
    Dim b64Enc As Object
    Dim utf8 As Object
    Dim Offset, Length, BlockSize As Integer
    
    Set b64Enc = CreateObject("System.Security.Cryptography.ToBase64Transform")
    Set utf8 = CreateObject("System.Text.UTF8Encoding")
    BlockSize = b64Enc.InputBlockSize
    For Offset = 0 To LenB(bytes) - 1 Step BlockSize
        Length = Min(BlockSize, UBound(bytes) - Offset)
        b64Block = b64Enc.TransformFinalBlock((bytes), Offset, Length)
        result = result & utf8.GetString((b64Block))
    Next
    B64Encode = result
End Function

Function B64Decode(b64Str)
    Dim utf8 As Object
    Dim bytes() As Byte
    Dim b64Dec As Object
    
    Set utf8 = CreateObject("System.Text.UTF8Encoding")
    Set b64Dec = CreateObject("System.Security.Cryptography.FromBase64Transform")
    bytes = utf8.GetBytes_4(b64Str)
    B64Decode = b64Dec.TransformFinalBlock((bytes), 0, UBound(bytes))
End Function

Function Encrypt(plaintext, aesKey)
    Dim aesKeyBytes, cipherBytes, plainBytes() As Byte
    Dim aesEnc As Object
    Dim utf8 As Object
    Dim AES As Object
    Dim aesIV() As Byte
    Set AES = CreateObject("System.Security.Cryptography.RijndaelManaged")
   
    Set utf8 = CreateObject("System.Text.UTF8Encoding")
    'Set aesIV = AES.GenerateIV
    aesKeyBytes = B64Decode(aesKey)
    'Set aesEnc = AES.CreateEncryptor_2((aesKeyBytes), aesIV)
    plainBytes = utf8.GetBytes_4(plaintext)
    cipherBytes = AES.CreateEncryptor.TransformFinalBlock((plainBytes), 0, UBound(plainBytes))
    Encrypt = B64Encode(cipherBytes)
End Function

Error on windows server 2019

The line Set aes = CreateObject ("System.Security.Cryptography.RijndaelManaged") gives the following error
(null): 0x80131509

I run this command to check class. Everything is regular.
powershell -Command [System.Reflection.Assembly] :: GetAssembly ('System.Security.Cryptography.RijndaelManaged')

GAC Version Location


True v4.0.30319 C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ mscorlib.dll

How can I solve?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.