2016-06-21 79 views
2

我一直在试图解决为什么在Vista SP2机器上编写和编译VB6应用程序中的元素在该机器上完美工作,但没有在64位Windows 10机器上。为了提高调试功能,我在Excel VBA中复制了编码问题。适用于Vista机器,但不适用于Windows 10机器。VB代码使用advapi32.dll cryptverifysignature作品在Vista SP2不在Windows 10 64位

中的CryptoAPI电话都宣称正是如此:

Private Declare Function CryptVerifySignature _ 
Lib "advapi32.dll" _ 
    Alias "CryptVerifySignatureA" (_ 
     ByVal hHash As Long, _ 
     pbSignature As Byte, _ 
     ByVal dwSigLen As Long, _ 
     ByVal hPubKey As Long, _ 
     ByVal sDescription As String, _ 
     ByVal dwFlags As Long _ 
      ) As Long 

是在Windows 10的机器上失败的部分由上方和下方铁轨下面的高亮显示:

Private Function SignValidate(ByRef abData() As Byte, _ 
         ByRef abSigned() As Byte, _ 
         Optional bSigned As Boolean = True) As Long 
Dim hHash As Long 
Dim lngReturnValue As Long 
Dim lngSigLen As Long 
Dim abText() As Byte 
Dim strTxt As String 
Dim lngW As Long 
Dim lngX As Long 
Dim lngY As Long 

Dim abHashVal() As Byte 

SignValidate = -1 
ReDim abText(UBound(abData)) 
abText = abData 

'Create a hash object to sign/validate 
lngReturnValue = CryptCreateHash(hCryptProv, CALG_SHA, 0, 0, hHash) 
If lngReturnValue = 0 Then 
    'Set_locale regionalSymbol 
    Err.Raise Err.LastDllError, , "DLL error code shown above. Could not create a Hash Object (CryptCreateHash API)" 
End If 
'Hash the data 
lngW = UBound(abText) + 1 
lngReturnValue = CryptHashData(hHash, abText(0), lngW, 0) 
If lngReturnValue = 0 Then 
    'Set_locale regionalSymbol 
    Err.Raise Err.LastDllError, , "DLL error code shown above. Could not calculate a Hash Value (CryptHashData API)" 
End If 

If bSigned Then 
    'release old key pair handle 
    If hKeyPair <> 0 Then CryptDestroyKey hKeyPair 
    'get a handle to the signature key pair 
    lngReturnValue = CryptGetUserKey(hCryptProv, AT_SIGNATURE, hKeyPair) 
    If lngReturnValue = 0 Then 
     'Set_locale regionalSymbol 
     Err.Raise Err.LastDllError, , "DLL error code shown above. Could not obtain key pair" 
    End If 
    'Determine the size of the signature 
    lngReturnValue = CryptSignHash(hHash, AT_SIGNATURE, 0, 0, vbNull, lngSigLength) 
    If lngSigLength > 0 Then ReDim abSig(lngSigLength - 1) 
    'Sign the hash object 
    lngReturnValue = CryptSignHash(hHash, AT_SIGNATURE, 0, 0, abSig(0), lngSigLength) 
    If lngReturnValue = 0 Then 
     'Set_locale regionalSymbol 
     Err.Raise Err.LastDllError, , "DLL error code shown above. Could not sign the hash" 
    End If 
    ' the signature is now available 
    ' size returned array to signature length 
    ReDim abSigned(UBound(abSig)) 
    ' return the signature to the calling procedure 
    abSigned = abSig 
    SignValidate = 0 
Else 
    lngSigLength = UBound(abSigned) + 1 
    ReDim abSig(UBound(abSigned)) 
    abSig = abSigned ' load the Signature array 

'======================================================== 
    'this is the line where the actual validation is done 
    lngReturnValue = CryptVerifySignature(hHash, abSig(0), lngSigLength, hKeyPair, 0, 0) 
'======================================================== 
    If lngReturnValue = 0 Then 'some error occurred 
     SignValidate = Err.LastDllError 
    Else 
     SignValidate = 0 
    End If 
End If 
End Function 

在Windows 10机器突出显示的对CryptVerifySignature的调用失败,并返回等于NTE_BAD_SIGNATURE的Err.LastDllError。 Vista机器验证签名正常。

我花了几天的时间研究可能发生的事情。一切都无济于事。任何指针感激地接受

+2

Vista机器是64位的吗? – dbugger

+0

您可能需要使用条件编译属性。如果你有一个64位版本的办公室,VBA的版本不再是VBA6,而是VBA7。调用API /函数略有不同。从MS看到这篇文章。 https://msdn.microsoft.com/en-us/library/office/ee691831(v=office.14).aspx –

+0

感谢您的回复。 Vista机器是32位的。 Vista机器上的Excel 2003,Windows 10机器上的32位Excel 2016。我相信在VBA中失败的那一行是在编译的VB6程序中失败的那一行,其中对CryptVerifySignature的调用位于一个自定义DLL中。 –

回答

1

经过多次的挫折和毫无结果的研究,我终于发现问题所在。一路上,我发现问题完全源于代码的另一部分。我还发现这个问题也表现在Windows 10 32位上 - 所以不是64位的问题。

以前对CryptImportKey的调用错误地填充了dwflags参数,但似乎并未阻止在Vista 32位下成功调用CryptVerifySignature,即使调查时对CryptImportKey的调用失败。一旦CryptImportKey的dwflags参数被更正为CRYPT_EXPORTABLE或CRYPT_NO_SALT,它就成功了,并且在我能够测试的所有替代操作系统/位数组合下,对CryptVerifySignature的后续调用成功完成。

道歉和感谢所有寻求帮助的人。直到下一次。

0

编辑 - 我看不出什么毛病的声明或致电

我见过的唯一的选择就是改变字节的指针声明为ByVal pSignature Long,然后调用它使用varPtr(abSig(0)

但你的代码看起来很好 - 我很困惑


您的声明与Microsoft API声明不符。不知道这是设计使然,因为签名是一个字节的指针

根据文档

LPBYTE, BYTE will be : * ByRef Byte 

更改此设置(默认参数传递BYVAL)

pbSignature As Byte 

对此

ByRef pbSignature As Byte 
+0

谢谢你。我已经明白VB6的默认值(原始问题似乎表现出来了)是ByRef,但我认为明确无损,所以我将明确所有的声明,看看会发生什么。 –

+0

只需将所有默认声明更改为ByRef,失败与以前完全相同。 –

+0

只有pSignature应该是ByRef - 它是唯一的指针。我看到你正在传递字节数组的第一个元素 - 我将在上面编辑我的答案以获得另一个调用建议 – dbmitch