暗号化キーを使って電子署名を作成する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のようになります。
まず、電子署名を作成する際の元となる平文「ベース文字列」を組み立てます。ベース文字列は、(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のようになります。
まず、指定された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 |