簡體   English   中英

如何在Golang pbkdf2中模擬pbkdf2-scala的密碼hash

[英]How to simulate password hash of pbkdf2-scala in Golang pbkdf2

我們的應用程序使用庫 SecureHash object 來創建單向密碼: https://github.com/nremond/pbkdf2-scala/blob/master/src/main/scala/io/github/nremond/SecureHash。 scala

現在我的問題是我在 Go 中的代碼返回-1進行密碼檢查。

package main

import (
    "bytes"
    "crypto/rand"
    "crypto/sha512"
    "fmt"
    "golang.org/x/crypto/pbkdf2"
    "math/big"
    "strings"
)

func main() {
    iteration := 25000

    // Hash User input
    password := []byte("123")
    salt := "yCyQMMMBt1TuPa1F9FeKfT0yrNIF8tLB"
    key := pbkdf2.Key(password, []byte(salt), iteration, sha512.Size, sha512.New)

    // COMPARE PASSWORD fetched from DB
        // 123 hash in scala
    tokenS := strings.Split("$pbkdf2-sha512$25000$yCyQMMMBt1TuPa1F9FeKfT0yrNIF8tLB$TtQt5BZLs4qlA0YAkcGukZwu7pkxOLcxwuoQB3qNtxM", "$")
    passwordHashInDatabase := tokenS[4]
    out := bytes.Compare(key, []byte(passwordHashInDatabase))
    fmt.Println("out: ", out)
}

驗證失敗,因為:

  • 待驗證的hash, tokenS[4] ,長度為32字節,而計算出的hash, key ,長度為64字節,
  • 在計算 hash 之前,salt 不是 Base64 解碼的,
  • 比較時,要驗證的 hash 是 Base64 編碼的,而計算出的 hash 是原始的。

一個可能的修復是:

iteration := 25000

// Hash User input
password := []byte("123")
salt, _ := base64.RawStdEncoding.DecodeString("yCyQMMMBt1TuPa1F9FeKfT0yrNIF8tLB") // Fix 1: Base64 decode salt (Base64: without padding and with . instead of +)
key := pbkdf2.Key(password, []byte(salt), iteration, sha256.Size, sha512.New)     // Fix 2: Apply an output size of 32 bytes

// COMPARE PASSWORD fetched from DB
// 123 hash in scala
tokenS := strings.Split("$pbkdf2-sha512$25000$yCyQMMMBt1TuPa1F9FeKfT0yrNIF8tLB$TtQt5BZLs4qlA0YAkcGukZwu7pkxOLcxwuoQB3qNtxM", "$")
passwordHashInDatabase, _ := base64.RawStdEncoding.DecodeString(tokenS[4]) // Fix 3: Base64 decode the hash to be verified (Base64: without padding and with . instead of +)
out := bytes.Compare(key, passwordHashInDatabase) // better apply an constant-time comparison
fmt.Println("out: ", out) // 0

雖然此代碼適用於此特定令牌,但通常修改后的 Base64 與. 而不是+ (因此,如果.存在,則必須在 Base64 解碼之前將它們替換為+ )並且沒有填充(后者是在上面的代碼片段中使用base64.RawStdEncoding的原因)。

請注意,Go ( passlib package ) 有一個passlib實現,但它似乎基本上使用默認值(例如,pbkdf2-sha512 的 output 大小為 64 字節),因此不能直接在此處應用。
盡管如此,此實現可以用作您自己實現的藍圖(例如,關於 Base64 編碼、s.Base64Decode Base64Decode()恆定時間比較、s.SecureCompare SecureCompare() 、預防側信道攻擊等)。

你有幾個問題:

  • 在將鹽傳遞給pbkdf2.Key()之前,您不是 base64 解碼鹽,您也不是 base64 解碼從數據庫中獲取的密鑰,然后再將其與pbkdf2.Key()的結果進行比較。 另請注意,Scala 實現在 base64 解碼/編碼之前/之后進行了一些字符替換。 這也需要在 Go 實現中復制。

  • Scala 實現中的createHash()方法有一個默認為32dkLength參數。 在 Go 實現中,您改為提供sha512.Size的結果,該結果為64且不匹配。 我知道使用了默認值,因為數據庫中的值是 32 字節長。

這是一個匆忙修復的實現:

package main

import (
    "bytes"
    "crypto/sha512"
    "encoding/base64"
    "fmt"
    "log"
    "strings"

    "golang.org/x/crypto/pbkdf2"
)

func b64Decode(s string) ([]byte, error) {
    s = strings.ReplaceAll(s, ".", "+")
    return base64.RawStdEncoding.DecodeString(s)
}

func main() {
    iteration := 25000

    // Hash User input
    password := []byte("123")
    salt, err := b64Decode("yCyQMMMBt1TuPa1F9FeKfT0yrNIF8tLB")
    if err != nil {
        log.Fatal("Failed to base64 decode the salt: %s", err)
    }
    key := pbkdf2.Key(password, salt, iteration, 32, sha512.New)

    // COMPARE PASSWORD fetched from DB
    // 123 hash in scala
    tokens := strings.Split("$pbkdf2-sha512$25000$yCyQMMMBt1TuPa1F9FeKfT0yrNIF8tLB$TtQt5BZLs4qlA0YAkcGukZwu7pkxOLcxwuoQB3qNtxM", "$")
    passwordHashInDatabase, err := b64Decode(tokens[4])
    if err != nil {
        log.Fatal("Failed to base64 decode password hash from the database: %s", err)
    }
    fmt.Printf("%x\n%x\n", key, passwordHashInDatabase)
    fmt.Printf("%d\n%d\n", len(key), len(passwordHashInDatabase))
    out := bytes.Compare(key, passwordHashInDatabase)
    fmt.Println("out: ", out)
}

Output:

4ed42de4164bb38aa503460091c1ae919c2eee993138b731c2ea10077a8db713
4ed42de4164bb38aa503460091c1ae919c2eee993138b731c2ea10077a8db713
32
32
out:  0

Go 游樂場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM