[英]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)
}
驗證失敗,因為:
tokenS[4]
,長度為32字節,而計算出的hash, key
,長度為64字節,一個可能的修復是:
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()
方法有一個默認為32
的dkLength
參數。 在 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.