VB2008でadvapi32.dll を使ったMD5の取得


タバスコ  2009-02-06 19:44:09  No: 141469

こんにちわ、現在 advapi32.dll を使ってMD5のハッシュ値を取得しようと思ってます。

http://su-u.jp/juju/%B5%A4%A4%DE%A4%B0%A4%EC%C6%FC%B5%AD/2007-03-08.html
上記のサイト様のVBサンプルをVB2008のVB6アップデートツールで変換して
とりあえずビルドは出来る状態になったのですが、あるエラーで行き詰ってしまいました。

    Private Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Integer, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Integer, ByVal dwFlags As Integer) As Integer
    Private Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Integer, ByVal dwFlags As Integer) As Integer
    Private Declare Function CryptCreateHash Lib "advapi32.dll" (ByVal hProv As Integer, ByVal Algid As Integer, ByVal hKey As Integer, ByVal dwFlags As Integer, ByRef phHash As Integer) As Integer
    Private Declare Function CryptDestroyHash Lib "advapi32.dll" (ByVal hHash As Integer) As Integer
    'UPGRADE_ISSUE: パラメータ 'As Any' の宣言はサポートされません。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="FAE78A8D-8978-4FD4-8208-5B7324A8F795"' をクリックしてください。
    '** Any を String に変更
    Private Declare Function CryptHashData Lib "advapi32.dll" (ByVal hHash As Integer, ByRef pbData As String, ByVal cbData As Integer, ByVal dwFlags As Integer) As Integer
    'UPGRADE_ISSUE: パラメータ 'As Any' の宣言はサポートされません。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="FAE78A8D-8978-4FD4-8208-5B7324A8F795"' をクリックしてください。
    '** Any を String に変更
    Private Declare Function CryptGetHashParam Lib "advapi32.dll" (ByVal hHash As Integer, ByVal dwParam As Integer, ByRef pbData As String, ByRef pcbData As Integer, ByVal dwFlags As Integer) As Integer

    Private Const PROV_RSA_FULL As Integer = 1
    Private Const PROV_RSA_AES As Integer = 24
    Private Const CRYPT_VERIFYCONTEXT As Integer = &HF0000000

    Private Const HP_HASHVAL As Integer = 2
    Private Const HP_HASHSIZE As Integer = 4

    Private Const ALG_TYPE_ANY As Integer = 0
    Private Const ALG_CLASS_HASH As Integer = 32768

    Private Const ALG_SID_MD5 As Integer = 3
    Private Const ALG_SID_SHA_256 As Integer = 12

    Private Const CALG_MD5 As Integer = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD5)
    Private Const CALG_SHA_256 As Integer = (ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_SHA_256)

    ' Create Hash
    Private Function CreateHash(ByRef abytData() As Byte, ByVal lngAlgID As Integer) As String
        Dim hProv, hHash As Integer
        Dim abytHash(63) As Byte
        Dim lngLength As Integer
        Dim lngResult As Integer
        Dim strHash As String
        Dim i As Integer
        strHash = ""
        If CryptAcquireContext(hProv, vbNullString, vbNullString, IIf(lngAlgID >= CALG_SHA_256, PROV_RSA_AES, PROV_RSA_FULL), CRYPT_VERIFYCONTEXT) <> 0 Then
            If CryptCreateHash(hProv, lngAlgID, 0, 0, hHash) <> 0 Then
                lngLength = UBound(abytData) - LBound(abytData) + 1
                If lngLength > 0 Then lngResult = CryptHashData(hHash, abytData(LBound(abytData)), lngLength, 0) Else lngResult = CryptHashData(hHash, 0, 0, 0)
                If lngResult <> 0 Then
                    lngLength = UBound(abytHash) - LBound(abytHash) + 1
                    If CryptGetHashParam(hHash, HP_HASHVAL, abytHash(LBound(abytHash)), lngLength, 0) <> 0 Then
                        For i = 0 To lngLength - 1
                            '** Right同等のメソッド追加
                            strHash = strHash & Right("0" & Hex(abytHash(LBound(abytHash) + i)), 2)
                        Next
                    End If
                End If
                CryptDestroyHash(hHash)
            End If
            CryptReleaseContext(hProv, 0)
        End If
        CreateHash = LCase(strHash)
    End Function

    ' Create Hash From String(Shift_JIS)
    Private Function CreateHashString(ByVal strData As String, ByVal lngAlgID As Integer) As String
        'UPGRADE_ISSUE: 定数 vbFromUnicode はアップグレードされませんでした。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="55B59875-9A95-4B71-9D6A-7C294BF7139D"' をクリックしてください。
        '** StrConv(strData, vbFromUnicode) を StrData に変更
        CreateHashString = CreateHash(System.Text.UnicodeEncoding.Unicode.GetBytes(strData), lngAlgID)
    End Function

    ' Create Hash From File
    Private Function CreateHashFile(ByVal strFileName As String, ByVal lngAlgID As Integer) As String
        Dim abytData() As Byte
        Dim intFile As Short
        Dim lngError As Integer
        On Error Resume Next
        'UPGRADE_WARNING: Dir に新しい動作が指定されています。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"' をクリックしてください。
        If Len(Dir(strFileName)) > 0 Then
            intFile = FreeFile
            FileOpen(intFile, strFileName, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared)
            'UPGRADE_ISSUE: InputB 関数はサポートされません。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="367764E5-F3F8-4E43-AC3E-7FE0B5E074E2"' をクリックしてください。
            'UPGRADE_TODO: System.Text.UnicodeEncoding.Unicode.GetBytes() を使うためにコードがアップグレードされましたが、動作が異なる可能性があります。 詳細については、'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="93DD716C-10E3-41BE-A4A8-3BA40157905B"' をクリックしてください。
            '** InputB(LOF(intFile), intFile) を intFile に変更
            abytData = System.Text.UnicodeEncoding.Unicode.GetBytes(intFile)
            FileClose(intFile)
        End If
        lngError = Err.Number
        On Error GoTo 0
        If lngError = 0 Then CreateHashFile = CreateHash(abytData, lngAlgID) Else CreateHashFile = ""
    End Function

    ' MD5
    Public Function CreateMD5Hash(ByRef abytData() As Byte) As String
        CreateMD5Hash = CreateHash(abytData, CALG_MD5)
    End Function
    Public Function CreateMD5HashString(ByVal strData As String) As String
        CreateMD5HashString = CreateHashString(strData, CALG_MD5)
    End Function
    Public Function CreateMD5HashFile(ByVal strFileName As String) As String
        CreateMD5HashFile = CreateHashFile(strFileName, CALG_MD5)
    End Function

    ' Rightメソッド
    Public Shared Function Right(ByVal stTarget As String, ByVal iLength As Integer) As String
        If iLength <= stTarget.Length Then
            Return stTarget.Substring(stTarget.Length - iLength)
        End If
        Return stTarget
    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        CreateMD5HashFile("C:\テスト.txt")
    End Sub

以上、現在のコードです、長くてすみません;
変更ヶ所は'** と記入してる所です、殆ど理解出来てないので、まずい変更かもしれません;
現状の内容で実行すると(種類 'System.ExecutionEngineException' の例外がスローされました。)
と出てプログラムが落ちてしまいます。

ソースも理解出来てないので何処がおかしいかも解らない状態です。
親切な方、どうかご教授お願いします。。


Hongliang  2009-02-06 20:05:51  No: 141470

理解できないコードを使うと言うのは危険すぎると思いますが。

せっかく VB2008 使ってるのですから、古臭いコードなど捨て去って System.Security.Cryptography 名前空間のハッシュ計算用クラスを使ってはいかがでしょう。MD5CryptoServiceProvider とか用意されてますよ。


タバスコ  2009-02-06 20:19:58  No: 141471

Hongliangさん、返事有難うございます。
確かに理解できないコードを使うのは危険ですよね;

実はSystem.Security.Cryptography 名前空間をを使った方法はすでに作成済みなんです。
ですが、大きいファイルのハッシュ値も調べるのには時間がかかりすぎてしまうので
advapi32.dll なら結構早いと言う情報があったので使ってみたいんです。
それに、API は今まで一回しか使った事がないので、練習にもなるかと思いまして;

プログラムが旨く動くようになれば、じっくりコードを理解していこうと思ってます。
宜しくお願いします。。


Hongliang  2009-02-06 23:33:30  No: 141472

> advapi32.dll なら結構早いと言う情報があったので使ってみたいんです。
一体どこで手に入れた情報なのか気になります。
後ろに CryptoServiceProvider とつく System.Security.Cryptography 名前空間下のクラスは、基本的に OS の暗号化サービス、つまりは advapi を利用して処理を行っています。つまりタバスコさんが Declare でやろうとしていることを既に .NET Framework がやっていますので、早くなりようが無いはずです。実際、VC++ で適当に試してみましたが所要時間はほぼ同等でした。
// SHA-256 の方は WinXP の advapi ではサポートされてないらしいので、Managed な実装である .NET の SHA256Managed との速度差は計測できませんでしたが。

アンマネージ コードとの相互運用を勉強したいのなら、まずこれに目を通しておくべきです。
http://msdn.microsoft.com/ja-jp/library/sd10k43k.aspx
あるデータを渡すときにどう宣言するかという例も豊富に記載されています。


タバスコ  2009-02-07 02:43:24  No: 141473

Hongliangさん、ご返事有難うございます。
早いと言うのは私の思い込みだったみたいです;
MD5CryptoServiceProvider も advapi を利用した物だったんですか・・・
知識不足で全然知りませんでした、今回勉強になりました。
少しでも早くと思い試すだけでも試してみたかったのですが、無駄だったみたいですね;

アンマネージ コードとの相互運用、難しいですが参考になりそうです、有難うございます。

やはりファイルが大きい(1GB適度)と、何を使っても時間がかかりますかね?
もし、同サイズのファイルを高速に識別出来る良い方法ありましたら教えて欲しいです。。


  2009-02-08 06:44:35  No: 141474

全然関係ない話

>        If CryptAcquireContext(hProv,
>            If CryptCreateHash(hProv,
>                lngLength = UBound(ab
>                If lngLength > 0 Then
>                If lngResult <> 0 Then
>                    lngLength = UBound
>                    If CryptGetHashParam(
v                        For i = 0 To lngL
>                            '** Right同等
>                            strHash = st
>                        Next
>                    End If
>                End If
>                CryptDestroyHash(hHash)
>            End If
>            CryptReleaseContext(hProv, 0)
>        End If
>        CreateHash = LCase(strHash)

コンパイルで最適化されるのかもしれないですが
これだけIfとNextあると気持ち悪くないですか?

少なくとも人にとっては優しくなさそうです。


夏みかん  2009-02-12 08:11:17  No: 141475

> やはりファイルが大きい(1GB適度)と、何を使っても時間がかかりますかね?
> もし、同サイズのファイルを高速に識別出来る良い方法ありましたら教えて欲しいです。。
API 関連で
CreateFileMapping
FlushViewOfFile
MapViewOfFile
UnmapViewOfFile
を使ってみるのはどう?


タバスコ  2009-02-12 18:31:37  No: 141476

のさん、夏みかんさんご返事ありがとうございます。
>これだけIfとNextあると気持ち悪くないですか?
気持ち悪いと言うか、多いと何時も私は混乱しちゃいますね;
かと言って無理に少なくしようと下手に簡略するとパフォーマンスが低下
した経験があります;(処理回数が少ない所なら問題ないですが。)

>API 関連で CreateFileMapping ... を使ってみるのはどう?
共有メモリを作成してデータの比較をすると言う事でしょうか?
難しくてどういう手順でやれば良いか想像がつきません;
しかし API はどれも難しいですね、初心者の壁の一つです;

今、別の事をしているので、一段落したらじっくり調べてみます。
調べて解らなかったらまた質問させて頂きます。

とりあえず advapi32.dll の件は終わってるので、解決にした方が良いのかな?・・・


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加