I'm writing a VBA function in Microsoft Access to Encrypt / Decrypt text data using RSA keys.
The following works currently:
CreateObject("System.Security.Cryptography.RSACryptoServiceProvider")
CreateObject("System.Text.UTF8Encoding")
but this is not working:
CreateObject("System.Convert")
I did some research and came across this stackoverflow question: Can I call a static method of a C# class from VBA via COM?
So as it turns out, System.Convert is a static class so therefore it is unavailable to the COM object, and therefore unavailable to VBA.
I could wrap all my .NET stuff into my own class and then add it to Access as a reference, but its a little outside my comfort zone and I'd rather stay away from having to maintain custom references anyways for this specific project.
So rather than stay fixated on the System.Convert option, I thought about what my needs are specifically. I need to be able to:
The simplest option I see would be to write my own VBA code to convert between Base 64 and a byte array - however I see two pitfalls:
Given my concerns - Convert.FromBase64String seemed the best option since it keeps everything in .NET, but since I can't use it - I need an alternative.
If there were other standard .NET classes that provided the FromBase64String and ToBase64String functionality but were able to be instantiated via CreateObject - that would probably be the best option. I do not know of any however.
There are many VBA/VBScript/VB6 Base64 implementations that generate exactly the same results as .NET ToBase64String
for encoding and FromBase64String
for decoding.
You can find a VBA/VB6 example with full Base64 Encode and Decode functions here Base64 encoder/decoder in Visual Basic. The Base64 VB module bas file can be found here Base64Coder.bas.
Here are some screenshots from the same tests in C#
and VB6
. You can clearly see the results are the same for both languages:
C#
static void Main(string[] args)
{
Check("Aladdin:open sesame", "QWxhZGRpbjpvcGVuIHNlc2FtZQ=="); // example from RFC 2617)
Check("1", "MQ==");
Check("22", "MjI=");
Check("333", "MzMz");
Check("4444", "NDQ0NA==");
Check("55555", "NTU1NTU=");
Check("abc:def", "YWJjOmRlZg==");
Check("????", "Pz8/Pw==");
Check("abcdefghijklnmopqrstuvwxyz0123456789???", "YWJjZGVmZ2hpamtsbm1vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Pz8/");
}
private static void Check(string plainText, string base64Text)
{
string s1 = Base64Encode(plainText);
string s2 = Base64Decode(base64Text);
Debug.WriteLine("String: " + s2 + ", to Base64: " + s1);
if(s1 != base64Text || s2 != plainText)
Debug.WriteLine("Check failed for \"" + plainText + "\" / \"" + base64Text + "\".");
}
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
C# OUTPUT
VBA/VB6
Public Sub Main()
Check "Aladdin:open sesame", "QWxhZGRpbjpvcGVuIHNlc2FtZQ==" ' example from RFC 2617
Check "1", "MQ=="
Check "22", "MjI="
Check "333", "MzMz"
Check "4444", "NDQ0NA=="
Check "55555", "NTU1NTU="
Check "abc:def", "YWJjOmRlZg=="
Check "????", "Pz8/Pw=="
Check "abcdefghijklnmopqrstuvwxyz0123456789???", "YWJjZGVmZ2hpamtsbm1vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Pz8/"
End Sub
Private Sub Check(ByVal plainText As String, ByVal base64Text As String)
Dim s1 As String: s1 = Base64EncodeString(plainText)
Dim s2 As String: s2 = Base64DecodeString(base64Text)
Debug.Print "String: " & s2 & ", Base64: " & s1
If s1 <> base64Text Or s2 <> plainText Then _
Debug.Print "Check failed for """ & plainText & """ / """ & base64Text & """."
End Sub
VBA/VB6 OUTPUT