Int*_*net 4 cryptography sha256 go hmac scrypt
我遇到了一些我为密码认证库编写的Go代码的问题.一般的想法是提供2个函数,Check()和New(),它们都提供了密码和256位HMAC密钥.Check()函数还提供256位salt和256位散列,并返回一个布尔值.New()函数返回一个新的随机salt,它是相应的哈希值.这两个函数都依赖于辅助函数hash(),它使用scrypt进行键延长,并且可以生成输出哈希.
当我最初编写它时,这是有效的(事实证明,我已经使用了早期丢失的代码修订版生成的测试数据).
我现在遇到的问题是,当提供由旧版本代码生成的数据时,Check()函数似乎工作得很好,但现在似乎失败了代码自己的New()函数生成的任何数据(两者都使用底层的hash()函数).
我知道,我应该从一开始就有git版本控制代码!我现在已经吸取了教训.
我已将函数分组并将问题快速演示到一个.go文件中,如下所示,并添加了一些输出用于调试:
package main
import (
"code.google.com/p/go.crypto/scrypt"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"crypto/subtle"
"errors"
"fmt"
"io"
)
// Constants for scrypt. See code.google.com/p/go.crypto/scrypt
const (
KEYLENGTH = 32
N = 16384
R = 8
P = 1
)
// hash takes an HMAC key, a password and a salt (as byte slices)
// scrypt transforms the password and salt, and then HMAC transforms the result.
// Returns the resulting 256 bit hash.
func hash(hmk, pw, s []byte) (h []byte, err error) {
sch, err := scrypt.Key(pw, s, N, R, P, KEYLENGTH)
if err != nil {
return nil, err
}
hmh := hmac.New(sha256.New, hmk)
hmh.Write(sch)
h = hmh.Sum(nil)
hmh.Reset() // Probably not necessary
return h, nil
}
// Check takes an HMAC key, a hash to check, a password and a salt (as byte slices)
// Calls hash().
// Compares the resulting 256 bit hash against the check hash and returns a boolean.
func Check(hmk, h, pw, s []byte) (chk bool, err error) {
// Print the input hash
fmt.Printf("Hash: %x\nHMAC: %x\nSalt: %x\nPass: %x\n", h, hmk, s, []byte(pw))
hchk, err := hash(hmk, pw, s)
if err != nil {
return false, err
}
// Print the hash to compare against
fmt.Printf("Hchk: %x\n", hchk)
if subtle.ConstantTimeCompare(h, hchk) != 1 {
return false, errors.New("Error: Hash verification failed")
}
return true, nil
}
// New takes an HMAC key and a password (as byte slices)
// Generates a new salt using "crypto/rand"
// Calls hash().
// Returns the resulting 256 bit hash and salt.
func New(hmk, pw []byte) (h, s []byte, err error) {
s = make([]byte, KEYLENGTH)
_, err = io.ReadFull(rand.Reader, s)
if err != nil {
return nil, nil, err
}
h, err = hash(pw, hmk, s)
if err != nil {
return nil, nil, err
}
fmt.Printf("Hash: %x\nSalt: %x\nPass: %x\n", h, s, []byte(pw))
return h, s, nil
}
func main() {
// Known values that work
pass := "pleaseletmein"
hash := []byte{
0x6f, 0x38, 0x7b, 0x9c, 0xe3, 0x9d, 0x9, 0xff,
0x6b, 0x1c, 0xc, 0xb5, 0x1, 0x67, 0x1d, 0x11,
0x8f, 0x72, 0x78, 0x85, 0xca, 0x6, 0x50, 0xd0,
0xe6, 0x8b, 0x12, 0x9c, 0x9d, 0xf4, 0xcb, 0x29,
}
salt := []byte{
0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20,
0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x4, 0x97,
0x48, 0x44, 0xe3, 0x7, 0x4a, 0xe8, 0xdf, 0xdf,
0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42, 0xfc, 0xd0,
}
hmac := []byte{
0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48,
0x46, 0x1c, 0x6, 0xcd, 0x81, 0xfd, 0x38, 0xeb,
0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e,
0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2,
}
// Check the known values. This Works.
fmt.Println("Checking known values...")
chk, err := Check(hmac, hash, []byte(pass), salt)
if err != nil {
fmt.Printf("%s\n", err)
}
fmt.Printf("%t\n", chk)
fmt.Println()
// Create new hash and salt from the known HMAC and Salt
fmt.Println("Creating new hash and salt values...")
h, s, err := New(hmac, []byte(pass))
if err != nil {
fmt.Printf("%s\n", err)
}
// Check the new values. This Fails!
fmt.Println("Checking new hash and salt values...")
chk, err = Check(hmac, h, []byte(pass), s)
if err != nil {
fmt.Printf("%s\n", err)
}
fmt.Printf("%t\n", chk)
}
Run Code Online (Sandbox Code Playgroud)
我在Linux 64bit和Windows8 64bit上都尝试了这个,但两者都失败了.
任何帮助将非常感激!就像我说的那样,我确实在某些方面有这个工作,但我似乎已经在某个地方打破了它.我通常只发现它在编写单元测试时不起作用......我想这就是他们的目的!
谢谢,
麦克风.
你似乎已经hash()在你的一个函数中颠倒了参数.在Check(),您有:
hchk, err := hash(hmk, pw, s)
Run Code Online (Sandbox Code Playgroud)
在New()你有:
h, err = hash(pw, hmk, s)
Run Code Online (Sandbox Code Playgroud)
这些显然不会产生导致验证失败的相同结果.
有三个类似的论点,像这样的相同类型,这样的错误并不太令人惊讶.也许值得一看,你是否可以重组一些东西让类型系统捕获这类错误?
| 归档时间: |
|
| 查看次数: |
1148 次 |
| 最近记录: |