提醒:本页面将不再更新、维护或者支持,文章、评论所叙述内容存在时效性,涉及技术细节或者软件使用方面不保证能够完全有效可操作,请谨慎参考!

其实很早就想介绍这个Windows内置的ActiveX/COM组件,我 前面有一篇文章 介绍如何借用.NET Framework实现类似于SHA1和MD5哈希算法,如果大家对此感兴趣也可以看一下。

好,言归正传,今天我要介绍的是如何让VBScript利用Windows原生自带的CAPICOM组件来实现随机数、Hash(MD5/SHA1)以及Base64算法,当然在VBScript的世界里,这些算法都有免组件的纯代码实现,当然使用组件的好处就是代码简洁和运行效率的提高,所以我们不妨尝试一下。 既然今天介绍的主角是CAPICOM,当然我们要推荐参考 微软的MSDN文档 ,大家不妨先大致浏览一番,可能大家很快发现下面这段提示:

CAPICOM is a 32-bit only component that is available for use in the following operating systems: Windows Server 2008, Windows Vista and Windows XP. Instead, use the .NET Framework to implement security features.

由此可见非常遗憾的是CAPICOM仅仅是32位Windows XP、Windows Vista以及Windows 2008系统上才自带(对于64位系统可以参考文章 在64位系统中使用CAPICOM ),所以在包含CAPICOM特性代码部署到服务器上之前需要测试一下当前系统是否支持,如果不支持只有考虑.NET或者原生代码的实现了。

CAPICOM有很多对象(Objects),这里我也不一一介绍,主要关注的是 CAPICOM.Utilities CAPICOM.HashedData 。本文也是通过这两个对象实现所需要的算法功能的。

CAPICOM.Utilities

实现随机数

Function GetRandom()
    Dim objCapiCom
    Set objCapiCom = CreateObject("CAPICOM.Utilities.1")
    GetRandom = objCapiCom.GetRandom(32, -1)
    Set objCapiCom = Nothing
End Function

可能大家要问为什么VBScript语言自带随机数功能,我们还需要使用CAPICOM来生成随机数,实际上我们通过脚本语言生成的随机数是伪随机数,当然这些伪随机数可以应用于一些要求不高的场合,伪随机数是通过算法和数学运算生成的模拟随机数,对于加密这类应用来说这种随机数是不安全的,而真正的随机数是通过硬件噪音生成的,比如在Linux及其他类Unix系统下,可以通过 /dev/random 或者 /dev/urandom 获得,因为这里我们实现的系统是Windows,所以可以变通的通过CAPICOM获取。

大家可能注意到上述代码 objCapiCom.GetRandom(32, -1) 中的第二个参数 -1 ,微软给出的定义如下:

Const CAPICOM_ENCODE_ANY    = -1
Const CAPICOM_ENCODE_BASE64 =  0
Const CAPICOM_ENCODE_BINARY =  1

关于这些常量定义的实际含义可以 参考MSDN文档

实现Base64编码和解码

在文章 《Base64 の処理》 有很好的例子。我简写如下:

Class Base64
    Private objCapiCom

    Private Sub Class_Initialize()
        Set objCapiCom = CreateObject("CAPICOM.Utilities")
    End Sub

    Private Sub Class_Terminate()
        Set objCapiCom = Nothing
    End Sub

    Public Function encode(str)
        encode = objCapiCom.Base64Encode(str)
    End Function

    Public Function decode(str)
        decode = objCapiCom.Base64Decode(str)
    End Function
End Class

' Set objBase64 = New Base64
' MsgBox objBase64.decode(objBase64.encode("Hello World"))
' Set objBase64 = Nothing

原文还介绍了如何对而进制文件进行Base64编解码,用到了 ByteArrayToBinaryString BinaryStringToByteArray 方法:

<!--METADATA TYPE="TypeLib" UUID="{EF53050B-882E-4776-B643-EDA472E8E3F2}" -->
<%
    Call Response.AddHeader( "Content-Type", "text/html; Charset=shift_jis" )

    Set Stream = Server.CreateObject("ADODB.Stream")
    Set CAPIUtil = Server.CreateObject( "CAPICOM.Utilities" )

    Stream.Open
    Stream.Type = adTypeBinary
    Stream.LoadFromFile Server.MapPath( "sample.jpg" )
    strFile = CAPIUtil.ByteArrayToBinaryString( Stream.Read )
    Stream.Close

    strEncoded = CAPIUtil.Base64Encode( strFile )

    ' バイナリデータを通常文字列として処理

    strDecoded = CAPIUtil.Base64Decode( strEncoded )

    strFile2 = CAPIUtil.BinaryStringToByteArray( strDecoded )

    Stream.Open
    Stream.Type = adTypeBinary
    Stream.Write strFile2
    Stream.SaveToFile Server.MapPath("sample2.jpg"), _
        adSaveCreateOverWrite 
    Stream.Close

%>

关于Base64的其他实现办法,可以参考我前面的一篇文章 《Base24、Base64编码的几种程序实现》

CAPICOM.HashedData

实现常用的哈希函数

这里主要参考了 《CAPICOM.dll을 이용한 Classic ASP(VBScript)에서 MD5 암호화 적용하기》 ,用到了一个Unicode字符串转换为Byte字符串的函数 UStr2Bstr ,当然为了便于理解,我还 找到了 逆函数 BStr2UStr

Function BStr2UStr(BStr)
    'Byte string to Unicode string conversion
    Dim lngLoop
    BStr2UStr = ""
    For lngLoop = 1 to LenB(BStr)
        BStr2UStr = BStr2UStr & Chr(AscB(MidB(BStr,lngLoop,1))) 
    Next
End Function

Function UStr2Bstr(UStr)
    'Unicode string to Byte string conversion
    Dim lngLoop
    Dim strChar
    UStr2Bstr = ""
    For lngLoop = 1 to Len(UStr)
        strChar = Mid(UStr, lngLoop, 1)
        UStr2Bstr = UStr2Bstr & ChrB(AscB(strChar))
    Next
End Function

比如常见的MD5实现代码如下:

Function MD5(str)
    Dim objCapiCom
    Set objCapiCom = CreateObject("CAPICOM.HashedData")
        objCapiCom.Algorithm = 3
        objCapiCom.Hash UStr2Bstr(str)
        MD5 = objCapiCom.Value
    Set objCapiCom = Nothing
End Function

' MsgBox MD5("123456")

同样的大家也许注意到了 objCapiCom.Algorithm ,属性3指明了所使用的哈西算法,主要的算法定义有以下列表,这些同样可以 从MSDN中找到

Const CAPICOM_HASH_ALGORITHM_SHA1   = 0
Const CAPICOM_HASH_ALGORITHM_MD2    = 1
Const CAPICOM_HASH_ALGORITHM_MD4    = 2
Const CAPICOM_HASH_ALGORITHM_MD5    = 3
Const CAPICOM_HASH_ALGORITHM_SHA256 = 4
Const CAPICOM_HASH_ALGORITHM_SHA384 = 5
Const CAPICOM_HASH_ALGORITHM_SHA512 = 6

同Base64编码解码一样,哈希函数也可以对二进制数据进行操作,具体做法是直接使用 Hash 方法分块哈希二进制数据,具体可以参考 Demon为我们提供的代码

Function md5_file(filename, raw_output)
    Dim HashedData, Utility, Stream
    Set HashedData = CreateObject("CAPICOM.HashedData")
    Set Utility = CreateObject("CAPICOM.Utilities")
    Set Stream = CreateObject("ADODB.Stream")
    HashedData.Algorithm = 3
    Stream.Type = 1
    Stream.Open
    Stream.LoadFromFile filename
    Do Until Stream.EOS
        HashedData.Hash Stream.Read(1024)
    Loop
    If raw_output Then
        md5_file = Utility.HexToBinary(HashedData.Value)
    Else
        md5_file = HashedData.Value
    End If
End Function