Aes.vbs
AES-256-CBC Encrypt and Decrypt Functions in VBScript
Install / Use
/learn @susam/Aes.vbsREADME
AES-256-CBC in VBScript
This project provides VBScript functions to perform encryption and decryption with AES-256-CBC.
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
- Why?
- Demo Script
- Demo Output
- Example Ciphertexts
- Crypto Properties
- OpenSSL CLI Examples
- Questions and Answers
- References
- License
- Support
Features
Here are some of the features of this project:
-
Works with Base64 encoded keys.
-
Exposes two simple functions named
Encrypt()andDecrypt()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 byDecrypt()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 toDecrypt(). 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 namedaes.incand include it in ASP files with an#includedirective 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
aesobject (of classRijndaelManaged) has a default key size of 256 bits. - The block size is 128 bits. The mode is 1, i.e., CBC. See
RijndaelManaged.ModeandCipherModedocumentation to confirm that the default mode is indeed CBC. - The padding mode is 2, i.e., PKCS #7. See
RijndaelManaged.PaddingandPaddingModedocumentation 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:
-
Encrypt the plaintext
hellowith 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 encryptThe output should match the string in the
encrypted2value. -
Verify MAC and decrypt t
