2017-08-07 59 views
0

最近,我一直在深入研究密码学,并获得在Excel中工作的散列和加密函数,我可能会在我正在使用的项目中使用这些函数。PBKDF2 Excel UDF以及如何连接INT(i)

我简单的散列函数使用的工作,例如:

Function Hash(ByVal plainText As String) 

    Dim utf8Encoding As Object 
    Dim hashManager As Object 
    Dim hashBytes() As Byte 

    Set utf8Encoding = CreateObject("System.Text.UTF8Encoding") 
    Set hashManager = CreateObject("System.Security.Cryptography.SHA512Managed") 
    hashBytes = utf8Encoding.GetBytes_4(plainText) 
    hashBytes = hashManager.ComputeHash_2(hashBytes) 

    Hash = Encode(hashBytes, edHex) 

    Set utf8Encoding = Nothing 
    Set hashManager = Nothing 

End Function 

要编码的结果我有一个创建了一个功能:

Function Encode(ByRef arrData() As Byte, ByVal dataType As endecodeDataType) As String 

    Dim domDoc As Object 
    Set domDoc = CreateObject("MSXML2.DOMDocument") 

    With domDoc 
     .LoadXML "<root />" 
     Select Case dataType 
      Case edBase64 
       .DocumentElement.dataType = "bin.base64" 
      Case edHex 
       .DocumentElement.dataType = "bin.hex" 
     End Select 
     .DocumentElement.nodeTypedValue = arrData 
    End With 

    Encode = domDoc.DocumentElement.Text 

    Set domDoc = Nothing 

End Function 

这些组合给了我完全可验证的结果。 更多的研究后,我现在工作的一个PBKDF2功能:

我第一次尝试寻找到 'Rfc2898DeriveBytes' 如下:

Dim hashManager As Object 
Set hashManager = CreateObject("System.Security.Cryptography.Rfc2898DeriveBytes") 

但是,这给出了一个错误,指出无法创建ActiveX组件。

除了错误和试图了解PBKDF2的基本知识,学习是为了与比特/字节工作,我创建了以下功能:

编辑:现在我只关注上为dkLen < =为hLen

Function PBKDF2(ByVal password As String, _ 
       ByVal hashIterations As Long, _ 
       ByVal salt As String, _ 
     Optional ByVal encodeHash As hashEncoding = heBase64) As Variant 

    Dim utf8Encoding As Object 
    Dim hashManager As Object 

    Dim hmacKeyBytes() As Byte 
    Dim saltBytes() As Byte 

    Dim hmacBytes() As Byte 
    Dim tempBytes() As Byte 

    Dim i As Long 

    'Create encoding and crypto objects 
    Set utf8Encoding = CreateObject("System.Text.UTF8Encoding") 
    Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA1") 

    'Encode the key and salt to bytes 
    hmacKeyBytes = utf8Encoding.GetBytes_4(password) 
    saltBytes = utf8Encoding.GetBytes_4(salt) 

    'Concatenate salt and INT(i) - INT (i) is a four-octet encoding of the integer i, most significant octet first. 

    'Set the key in the crypto class 
    hashManager.key = hmacKeyBytes 

    'Compute HMAC from salt 
    hmacBytes = hashManager.ComputeHash_2(saltBytes) 
    tempBytes = hmacBytes 

    'HMAC iterations 
    For i = 1 To hashIterations 
     tempBytes = hashManager.ComputeHash_2(tempBytes) 
     hmacBytes = XorBytes(tempBytes, hmacBytes) 
    Next i 

    'ToDo: extract the first dkLen octets to produce a derived key DK 

    'Base64, Hex, or Byte() output 
    If encodeHash = heBase64 Then 
     PBKDF2 = Encode(hmacBytes, edBase64) 
    ElseIf encodeHash = heHex Then 
     PBKDF2 = Encode(hmacBytes, edHex) 
    End If 

    Set hashManager = Nothing 
    Set utf8Encoding = Nothing 

End Function 

哪里定义给xorBytes为:

Function XorBytes(ByRef byte1() As Byte, ByRef byte2() As Byte) As Byte() 

    Dim tempBytes() As Byte 
    Dim len1 As Long 
    Dim i As Long 

    len1 = UBound(byte1) 
    ReDim tempBytes(len1) 

    For i = 0 To len1 
     tempBytes(i) = byte1(i) Xor byte2(i) 
    Next i 

    XorBytes = tempBytes 

End Function 

我相信我的基本知识是正确的。我不知道如何解决的一件事是如何将INT(i)连接到salt。规格状态:

U_1 = PRF(P,S || INT(i))的

这里,INT(i)是对整数i的四个八位字节的编码,最显著八位位组第一位。

如何在我的VBA代码中实现这个功能?我希望这使我接近这个测试向量:

  • 输入
    • P = “密码”(8个字节)
    • S = “盐”(4个八比特组)
    • C = 1
    • 为dkLen = 20
  • 输出
    • DK = 0C 60 C8 0F 96 1F 0E 71 F3 A9 B5 24 AF 60 12 06 2F E0 37 A6(20个八位字节)

回答

0

后一些更摆弄以下函数返回输出,我可以验证搭配:

https://tools.ietf.org/html/rfc6070

枚举

Enum hmacAlgorithm 
    HMAC_MD5 
    HMAC_SHA1 
    HMAC_SHA256 
    HMAC_SHA384 
    HMAC_SHA512 
End Enum 

Enum hashEncoding 
    heBase64 
    heHex 
    heNone_Bytes 
End Enum 

PBKDF2功能

Function PBKDF2(ByVal password As String, _ 
    ByVal salt As String, _ 
    ByVal hashIterations As Long, _ 
    ByVal algoritm As hmacAlgorithm, _ 
    Optional ByVal dkLen As Long, _ 
    Optional ByVal encodeHash As hashEncoding = heBase64) As Variant 

'https://tools.ietf.org/html/rfc2898 - PKCS #5: Password-Based Cryptography Specification Version 2.0 
'https://tools.ietf.org/html/rfc6070 - PKCS #5: Password-Based Key Derivation Function 2 (PBKDF2) Test Vectors 
'https://en.wikipedia.org/wiki/PBKDF2 

'DK = T1 || T2 || ... || Tdklen/hlen 
'Ti = F(password, salt, c, i) 
' 
'F(Password, Salt, c, i) = U1^U2^...^Uc 
' 
'U_1 = PRF (P, S || INT (i)) (INT (i) is a four-octet encoding of the integer i, most significant octet first.) 
'U_2 = PRF (P, U_1) 
'... 
'U_c = PRF (P, U_{c-1}) 

Dim utf8Encoding As Object 
Dim hashManager As Object 

Dim hLen As Long 
Dim noBlocks As Long 
Dim noBlock As Long 

Dim hmacKeyBytes() As Byte 
Dim saltBytes() As Byte 
Dim uboundSaltBytes As Long 

Dim hmacBytes() As Byte 
Dim tempBytes() As Byte 
Dim outputBytes() As Byte 

Dim i As Long 
Dim j As Long 

'Create utf8-encoding object 
Set utf8Encoding = CreateObject("System.Text.UTF8Encoding") 

'Create hmac object 
Select Case algoritm 
    Case HMAC_MD5 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACMD5") 
    Case HMAC_SHA1 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA1") 
    Case HMAC_SHA256 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA256") 
    Case HMAC_SHA384 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA384") 
    Case HMAC_SHA512 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA512") 
End Select 

'Check the length of the blocks to be generated 
hLen = hashManager.HashSize/8 

'Calculate amount of blocks 'T' 
If dkLen = 0 Then dkLen = hLen 
noBlocks = Application.WorksheetFunction.Ceiling(dkLen/hLen, 1) 

'Encode the key and salt to bytes 
hmacKeyBytes = utf8Encoding.GetBytes_4(password) 
saltBytes = utf8Encoding.GetBytes_4(salt) 

'Set the key in the crypto class 
hashManager.key = hmacKeyBytes 

'Get the length of the salt, add 4 to concatenate INT(I) 
uboundSaltBytes = UBound(saltBytes) + 4 

'Loop T1 || T2 || ... || Tdklen/hlen 
For i = 1 To noBlocks 

    'Salt || INT(i) 
    'INT (i) is a four-octet encoding of the integer i, most significant octet first. 
    tempBytes = saltBytes 
    ReDim Preserve tempBytes(uboundSaltBytes) 
    noBlock = i 

    'Calculate INT(i) of Salt || INT(i) 
    For j = 3 To 0 Step -1 
     tempBytes(uboundSaltBytes - j) = Int(noBlock/(255^j)) 
     noBlock = noBlock - Int(noBlock/(255^j)) * 255^j 
    Next j 

    'Hash U1: Salt || INT(i) 
    hmacBytes = hashManager.ComputeHash_2(tempBytes) 
    tempBytes = hmacBytes 

    'Hash, Xor: U1^U2^...^Uc 
    For j = 1 To hashIterations - 1 
     hmacBytes = hashManager.ComputeHash_2(hmacBytes) 
     tempBytes = XorBytes(tempBytes, hmacBytes) 
    Next j 

    'For the first block outputBytes() is empty 
    If i = 1 Then 
     outputBytes = tempBytes 
    Else 
     ConcatenateArrayInPlace outputBytes, tempBytes 
    End If 

Next i 

'Extract the first dkLen octets to produce a derived key DK: 
ReDim Preserve outputBytes(dkLen - 1) 

'Base64, Hex, or Byte() output 
If encodeHash = heBase64 Then 
    PBKDF2 = Encode(outputBytes, edBase64) 
ElseIf encodeHash = heHex Then 
    PBKDF2 = Encode(outputBytes, edHex) 
Else 
    PBKDF2 = outputBytes 
End If 

Set hashManager = Nothing 
Set utf8Encoding = Nothing 

End Function 

HMAC功能

Function HMAC(ByVal plainText As String, _ 
    ByVal algoritm As hmacAlgorithm, _ 
    Optional ByVal key As String, _ 
    Optional ByVal decodeKey As keyDecoding = kdNone_String, _ 
    Optional ByVal encodeHash As hashEncoding = heBase64) As Variant 

Dim hashManager As Object 

Dim hashBytes() As Byte 
Dim hmacKeyBytes() As Byte 

'Create the specific hash manager based on the hash algoritm 
Select Case algoritm 
    Case HMAC_MD5 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACMD5") 'Returns 128 bits, 16 bytes 
    Case HMAC_SHA1 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA1") 'Returns 160 bits, 20 bytes 
    Case HMAC_SHA256 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA256") 'Returns 256 bits, 32 bytes 
    Case HMAC_SHA384 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA384") 'Returns 384 bits, 48 bytes 
    Case HMAC_SHA512 
     Set hashManager = CreateObject("System.Security.Cryptography.HMACSHA512") 'Returns 512 bits, 64 bytes 
End Select 

'Encode the plaintText to bytes 
hashBytes = UTF8_GetBytes(plainText) 

If key = vbNullString Then 

    'Get the key generated by the hashManager 
    hmacKeyBytes = hashManager.key 

    'Calculate the hash 
    hashBytes = hashManager.ComputeHash_2(hashBytes) 

    'Return encoded result 
    If encodeHash = heBase64 Then 
     HMAC = "<Key>" & Encode(hmacKeyBytes, edBase64) & "<Key>" & vbCrLf & Encode(hashBytes, edBase64) 
    ElseIf encodeHash = heHex Then 
     HMAC = "<Key>" & Encode(hmacKeyBytes, edHex) & "<Key>" & vbCrLf & Encode(hashBytes, edHex) 
    End If 

Else 

    'Decode and set the key 
    Select Case decodeKey 
    Case kdBase64 
     hashManager.key = Decode(key, edBase64) 
    Case kdHex 
     hashManager.key = Decode(key, edHex) 
    Case Else 
     hashManager.key = UTF8_GetBytes(key) 
    End Select 

    'Calculate the hash 
    hashBytes = hashManager.ComputeHash_2(hashBytes) 

    'Return encoded result 
    If encodeHash = heBase64 Then 
     HMAC = Encode(hashBytes, edBase64) 
    ElseIf encodeHash = heHex Then 
     HMAC = Encode(hashBytes, edHex) 
    End If 

End If 

Set hashManager = Nothing 

End Function 

测试子程序:

Sub PBKDF2_Test() 

Dim testvector As String 
Dim pbkdf2_result As String 

pbkdf2_result = PBKDF2("password", "salt", 1, HMAC_SHA1, 20, heHex) 
testvector = "0c60c80f961f0e71f3a9b524af6012062fe037a6" 
If pbkdf2_result = testvector Then Debug.Print "TV1: OK" Else Debug.Print "TV1: FAULT" 

pbkdf2_result = PBKDF2("password", "salt", 2, HMAC_SHA1, 20, heHex) 
testvector = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957" 
If pbkdf2_result = testvector Then Debug.Print "TV2: OK" Else Debug.Print "TV2: FAULT" 

pbkdf2_result = PBKDF2("password", "salt", 4096, HMAC_SHA1, 20, heHex) 
testvector = "4b007901b765489abead49d926f721d065a429c1" 
If pbkdf2_result = testvector Then Debug.Print "TV3: OK" Else Debug.Print "TV3: FAULT" 

pbkdf2_result = PBKDF2("passwordPASSWORDpassword", "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, HMAC_SHA1, 25, heHex) 
testvector = "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038" 
If pbkdf2_result = testvector Then Debug.Print "TV4: OK" Else Debug.Print "TV4: FAULT" 

End Sub 

我想不是最漂亮的代码,但它是向前迈进了一步。随意改善!

+0

其中是'endecodeDataType'定义? ..它是图书馆的一部分吗? – jsotola

+0

jsotola,我编辑了答案,包括使用的两个枚举和HMAC函数 – Jelmer

相关问题