[이동] PBKDF2 구현해보기
26330 단어 go
소개
이번에는 PBKDF2에 대한 기능을 구현해 보겠습니다.
마지막으로 ASP.NET Core Identity를 시도했을 때 PasswordHasher 클래스를 사용했습니다.
그리고 암호를 저장하기 위해 PBKDF2를 사용했습니다.
저번에 작성한 SHA-512함수와 HMAC-SHA512함수를 사용하겠습니다.
Go 패키지 사용
"golang.org/x/crypto/pbkdf2"로 PBKDF2 값을 생성할 수 있습니다.
소금 값이 필요합니다.
PasswordHasher 클래스는 "RandomNumberGenerator"를 사용하여 생성합니다.
지정된 길이의 난수를 생성합니다.
RandomNumberGenerator Class(System.Security.Cryptography) - Microsoft Learn
package main
import (
"crypto/rand"
"crypto/sha512"
"fmt"
"log"
"math"
"math/big"
"golang.org/x/crypto/pbkdf2"
)
func main() {
inputData := []byte("hello")
salt, err := generateRandomSalt(128 / 8)
if err != nil {
log.Panicln(err.Error())
}
result = ""
keyPkg := generatePDKDF2Package(inputData, salt, 100_000, 256/8)
for _, k := range keyPkg {
result += fmt.Sprintf("%02X", k)
}
log.Println(result)
...
}
// Generate a salt value
func generateRandomSalt(length int) ([]byte, error) {
results := make([]byte, length)
for i := 0; i < length; i++ {
salt, err := rand.Int(rand.Reader, big.NewInt(255))
if err != nil {
return nil, err
}
results[i] = byte(salt.Int64())
}
return results, nil
}
...
func generatePDKDF2Package(password []byte, salt []byte, iterateCount int, keyLength int) []byte {
return pbkdf2.Key(password, salt, iterateCount, keyLength, sha512.New)
}
결과
58A07933EA993981DBF1856FCCB708B522B0B0E6C8F192C3093307337E9CC747
자체 기능 작성
...
func main() {
inputData := []byte("hello")
salt, err := generateRandomSalt(128 / 8)
if err != nil {
log.Panicln(err.Error())
}
...
result = ""
keyPkg := generatePDKDF2Package(inputData, salt, 100_000, 256/8)
for _, k := range keyPkg {
result += fmt.Sprintf("%02X", k)
}
log.Println(result)
}
...
func generatePDKDF2(password []byte, salt []byte, iterateCount int, keyLength int) []byte {
hashLength := sha512.Size
// 1. dkLen > (2^32 - 1)
if keyLength > ((int(math.Exp2(32)) - 1) * hashLength) {
log.Println("derived key too long")
return nil
}
// 2. Block size
// l = CEIL (dkLen / hLen)
blockCount := int(math.Ceil(float64(keyLength) / float64(hashLength)))
// r = dkLen - (l - 1) * hLen
// r := keyLength - (blockCount-1)*hashLength
dk := make([]byte, hashLength*blockCount)
s := make([]byte, len(salt)+4)
copy(s, salt)
// 3. T_1 = F (P, S, c, 1) , 〜 T_l = F (P, S, c, l) ,
for blockIndex := 1; blockIndex <= blockCount; blockIndex++ {
// S || INT (i)
s[len(s)-4] = byte(blockIndex >> 24)
s[len(s)-3] = byte(blockIndex >> 16)
s[len(s)-2] = byte(blockIndex >> 8)
s[len(s)-1] = byte(blockIndex)
// U_1 = PRF (P, S || INT (i))
u := HashHMACSHA512(password, s)
// 4. DK = T_1 || T_2 || ... || T_l<0..r-1>
if blockIndex > 1 {
dk = append(dk, u[:]...)
} else {
dk = u[:]
}
// F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
for ci := 1; ci < iterateCount; ci++ {
u = HashHMACSHA512(password, u)
for ui := range u {
dk[ui+(hashLength*(blockIndex-1))] ^= u[ui]
}
}
}
return dk[:keyLength]
}
...
결과
58A07933EA993981DBF1856FCCB708B522B0B0E6C8F192C3093307337E9CC747
솔트 값과 반복 횟수를 추가하여 해시 값 생성
PasswordHasher 클래스는 사용자 암호를 저장하기 위해 해시 값을 생성합니다.
인증을 위해 동일한 암호에서 매번 동일한 해시 값을 생성해야 합니다.
따라서 해시된 비밀번호에 솔트 값과 반복 횟수를 추가해야 합니다.
"PasswordHasher.cs"에 따르면 해시된 암호 앞에 추가해야 합니다.
main.go
package main
import (
"crypto/rand"
"crypto/sha512"
"encoding/base64"
"fmt"
"log"
"math"
"math/big"
"golang.org/x/crypto/pbkdf2"
)
func main() {
...
keySelf := generatePDKDF2(inputData, salt, 100_000, 256/8)
...
// Add the salt value and the iteration count
outputBytes := make([]byte, len(keySelf)+len(salt)+13)
outputBytes[0] = 0x01
// In ASP.NET Core Identity, the value of "KeyDerivationPrf.HMACSHA512" is "2"
writeNetworkByteOrder(outputBytes, 1, 2)
writeNetworkByteOrder(outputBytes, 5, 100_000)
writeNetworkByteOrder(outputBytes, 9, uint(len(salt)))
blockCopy(salt, outputBytes, 13, len(salt))
blockCopy(keySelf, outputBytes, 13+len(salt), len(keySelf))
// Base64 encoding
output := base64.StdEncoding.EncodeToString(outputBytes)
log.Printf("Result : %s", output)
}
...
func writeNetworkByteOrder(buffer []byte, offset int, value uint) {
buffer[offset+0] = byte(value >> 24)
buffer[offset+1] = byte(value >> 16)
buffer[offset+2] = byte(value >> 8)
buffer[offset+3] = byte(value >> 0)
}
func blockCopy(src []byte, dst []byte, offset int, copyLength int) {
index := offset
for i := 0; i < copyLength; i++ {
dst[index] = src[i]
index += 1
}
}
결과
AQAAAAIAAYagAAAAEEZHtMLiF5yoYHif+AJgoy5QqO2CTfdOzoF7jkOM+omSShyzooRnwl1soh0xzLpbxg==
자원
Reference
이 문제에 관하여([이동] PBKDF2 구현해보기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/masanori_msl/go-try-pbkdf2-implementation-an1텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)