暗号化キーを使って電子署名を作成するVBA

手順2の部分のスクリプトは以下のようになります。

[リスト3]手順2.暗号化キーを使って電子署名を作成する

Private Sub MakeSign(ByVal phase As Integer, ByVal httpMethod As String, ByVal URL As String)

    Dim strBase As String '電子署名のベース文字列をセットする変数
    Dim cryptKey As String '電子署名の暗号化キーをセットする変数
    strBase = httpMethod & "&" & UrlEncode(URL) & "&" & UrlEncode(SortedParams(param))
    cryptKey = Range("consumer_secret") & "&" '暗号化キーの各フェーズ共通部分
    Select Case phase
        Case 2 'アクセス・キー取得フェーズの暗号化キー延長部分
            cryptKey = cryptKey & Range("request_secret")
        Case 3 'Webサービス利用フェーズの暗号化キー延長部分
            cryptKey = cryptKey & Range("access_secret")
    End Select
    param("oauth_signature") = UrlEncode(Hmac_sha1(cryptKey, strBase))

End Sub

仮引数phaseの意味は手順1と同様です。httpMethodはHTTPメソッド(POSTまたはGET)、URLはHTTP通信の送信先URLを受け取ります。電子署名の作成イメージは図6のようになります。

図6.電子署名の作成イメージ(フェーズ1の場合)

まず、電子署名を作成する際の元となる平文「ベース文字列」を組み立てます。ベース文字列は、(1)HTTPメソッド、(2)送信先URL、(3)OAuth引数、の3つを「&」で繋げます。(2)と(3)は繋げる前にURLエンコードを施す必要があります。また(3)は、引数名のアルファベット順に並べたうえで、引数名1=値1&引数名2=値2&・・・&引数名n=値n、という形に予め組み立てておく必要があります。この部分は、ユーザー定義関数sortedParamsで行っています(後述)。

続いて、暗号化キーを準備します。すべてのフェーズでコンシューマー・シークレットと「&」は必要です。これに。フェーズ2ではリクエスト・シークレット、フェーズ3ではアクセス・シークレットを繋いだものを暗号化キーとします。 ベース文字列と暗号化キーができたら、HMAC-SHA1方式を用いて電子署名を作成します。この部分は、ユーザー定義関数hmac_sha1で行っています。電子署名ができたらURLエンコードを施し、oauth_signature引数として追加します。

電子署名も含め、全ての引数を送信するVBA

手順3の部分のスクリプトは以下のようになります。

[リスト4]手順3.電子署名も含め、全ての引数を送信する

Private Sub SendHttp(ByVal httpMethod As String, ByVal URL As String)

    xmlhttp.Open httpMethod, URL, False
    xmlhttp.setRequestHeader "Authorization", "OAuth " & BuildHeader(param)
    xmlhttp.send
    Range("OAuthStatus") = xmlhttp.statusText 'リクエスト成否の状態を取得

End Sub

仮引数のhttpMethodとURLは、手順2と同様です。全ての引数を送信するイメージは、図7のようになります。

図7.全ての引数を送信するイメージ(フェーズ1の場合)

まず、指定されたHTTPメソッドに従って、送信先URLに対し、非同期でHTTP通信の接続を開きます。 次に、OAuthの引数をAuthorizationヘッダーとして設定します。この部分は、ユーザー定義関数buildHeader(後述)で行っています。そして、送信を行い、リクエスト成否の状態をワークシート上に保存します。

各種ユーザー定義関数

ユーザー定義関数SortedParamsは、以下のようになっています。

[リスト5]ユーザー定義関数SortedParams

Function SortedParams(ByVal param As Scripting.Dictionary) As String

    '(1)sortメソッドを利用するため、JScriptの準備
    Dim js As Object
    Set js = CreateObject("ScriptControl")
    js.Language = "jscript"

    '(2)JScriptの配列を用意し、引数を設定
    Dim ar As Object
    Set ar = js.eval("new Array")
    Dim i As Integer
    For i = 0 To param.Count - 1
        ar.push param.Keys(i) & "=" & param.Items(i)
    Next

    '(3)JScriptのsortメソッドを実行
    CallByName ar, "sort", VbMethod

    '(4)ソートされたJScript配列を「&」で繋いで出力
    SortedParams = Replace(ar, ",", "&")

End Function

VBAにはソート関数がないため、仮引数でOAuth引数の連想配列を受け取り、JScriptのsortメソッドを利用します。
(1)では、JScriptの準備をして、変数jsで利用できるようにしています。
(2)では、eval("new Array")メソッドを使って配列arを生成します。param連想配列(Scripting Dictionary)の要素を1つずつ取り出し、「引数名i=値i」という形の文字列にして、配列arに追加しています。VBAの連想配列は、Keys(i)でキー値、Items(i)でデータ値を取得できます。
(3)では、CallByNameを使って、配列arに対して、sortという名前の、メソッドを実行しています。
(4)では、「引数1=値1,・・・,引数n=値n」という形で格納されているarオブジェクトの「,」を「&」に置き換えて、目的の文字列を戻り値に返しています。

ユーザー定義関数BuildHeaderは、以下のようになっています。

[リスト6]ユーザー定義関数BuildHeader

Function BuildHeader(ByVal param As Scripting.Dictionary) As String

    Dim prm() As String '値渡しでも、オブジェクトはポインタになるので注意
    ReDim prm(param.Count - 1)
    Dim i As Integer
    For i = 0 To param.Count - 1
        prm(i) = param.Keys(i) & "=""" & param.Items(i) & """"
    Next
    BuildHeader = Join(prm, ", ")

End Function

仮引数でOAuth引数の連想配列を受け取り、文字列型配列prmを用意し、配列の大きさを連想配列の数に合わせています。For命令の中では、連想配列を「引数名i="値i"」という形に組み立て、連想配列の数だけprm(i)に設定しています。最後に、Join関数を使って、「引数1="値1", …, 引数n="値n"」という文字列を作成し、戻り値としています。

その他のユーザー定義関数については、名前と処理内容を示すに留めます。

表5.その他のユーザー定義関数

関数名 引数 戻り値 処理内容 呼び出し元プロシージャ・関数
UrlEncode str As String String JScriptの関数を使ってURLエンコードを施す cbAuth_Click
Hmac_sha1 key As String, msg As String String 暗号化キー(key)とベース文字列(msg)から電子署名された文字列を返す cbAuth_Click
Sha1 byteMsg() As Byte String sha1により暗号化を行う Hmac-sha
SeqFuncPlusK t As Integer, b As Long, c As Long, d As Long Long 循環型の変換処理を行う Sha1
Add X As Long, Y As Long Long sha1での加算を行う sha1, SeqFuncPlusK
RotateLeft bits As Integer, X As Long Long Xの左端「bits」ビット分を右端に回した値を計算する Sha1
DecToHex H() As Long String Long型配列を16進数の文字列に変換する Sha1
Hex2byte hex As String Byte() 16進数の文字列をバイト配列に変換する Hmac-sha1
EncodeBase64 data() As Byte String MSXMLの機能を使ってBase64エンコードを施す Hmac-sha1