PBKDF2 Excel UDF以及如何连接INT(i) [英] PBKDF2 Excel UDF and how to concatenate INT(i)

查看:93
本文介绍了PBKDF2 Excel UDF以及如何连接INT(i)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我一直在研究加密技术,并在Excel中使用散列和加密函数,这些函数可以在我正在研究的项目中使用。

Recently I have been digging into cryptography and getting hashing and encryption functions working in Excel which I might use in a project I am working on.

我得到了简单的散列使用的函数,例如:

I got simple hashing functions working using, for example:

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

要对结果进行编码,我创建了一个函数:

To encode the result I have a created a 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函数:

These combined gives me perfectly verifiable results. After more research I am now working on a PBKDF2 function:

  • Specs: https://tools.ietf.org/html/rfc2898
  • Test vectors: https://tools.ietf.org/html/rfc6070

我的第一次尝试是按如下方式查看 Rfc2898DeriveBytes:

My first attempt was to look into 'Rfc2898DeriveBytes' as follows:

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

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

However this gives an error stating that the ActiveX component cannot be created.

除了该错误之外,为了尝试理解PBKDF2的基础,并学习使用位/字节,我创建了以下函数:

Besides the error and for the sake of trying to understand the basics of PBKDF2, and learning to work with bits/bytes I have created the following function:

编辑:现在,我仅关注dkLen< = hLen

For now I'm only focusing on 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定义为:

Where I defined XorBytes as:

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)连接到盐上。规范指出:

I believe I have the basics correct. One thing I don't know how to solve is how to concatenate INT(i) to the salt. The specs state:


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

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

此处,INT(i)是整数i的四字节编码,最高有效八位字节在前。

Here, INT (i) is a four-octet encoding of the integer i, most significant octet first.

如何在我的VBA代码中实现这一点?我希望这使我更接近此测试向量:

How do I implement this in my VBA code? I hope this gets me closer to this test vector:


  • 输入


    • P =密码(8个八位字节)

    • S =盐(4个八位字节)

    • c = 1

    • dkLen = 20

    • Input
      • P = "password" (8 octets)
      • S = "salt" (4 octets)
      • 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个八位位组)

      推荐答案

      经过进一步摆弄之后,下面的函数返回了我可以验证的输出:

      After some more fiddling the function below returns output that I can verify with:

      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
      

      我想不是他最漂亮的代码,但这是向前的一步。随时改进!

      I guess not the prettiest code, but it's a step forward. Feel free to improve!

      这篇关于PBKDF2 Excel UDF以及如何连接INT(i)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆