2013-05-08 7 views
4

У меня возникла проблема с некоторым кодом Go, который я написал для библиотеки проверки подлинности паролей. Общая идея состоит в том, чтобы предоставить 2 функции: Check() и New(), которым предоставлены пароль и 256-битный ключ HMAC. Функция Check() также предоставляет 256-битную соль и 256-битный хеш и возвращает логическое значение. Функция New() возвращает новую случайную соль и соответствующий хеш. Обе функции полагаются на вспомогательную функцию, hash(), которая использует scrypt для удлинения ключа и выполняет реальную работу по генерации выходного хэша.Многократные вызовы Golang crypto имеют разные ответы

Это работало, когда я изначально написал его (о чем свидетельствует тот факт, что у меня есть тестовые данные, сгенерированные ранее потерянной версией кода).

Проблема, с которой я сталкиваюсь, заключается в том, что функция Check() работает отлично, когда она снабжена данными, сгенерированными старой версией кода, но теперь кажется, что сбой данных сгенерирован собственным кодом нового () (которые используют основную функцию 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) 
} 

Я попытался это как на Linux 64bit и Windows8 64bit, и он не работает на обоих.

Любая помощь была бы высоко оценена! Как я уже сказал, у меня есть , но я, кажется, сломал его где-то на этом пути. Я обычно обнаружил, что он не работает при написании модульных тестов ... Полагаю, для этого они нужны!

Thanks,

Mike.

+0

Почему вы используете HMAC и SHA-256, когда в scrypt уже используются оба? – Luke

+0

Я напрямую вызываю функции из обоих этих пакетов в строке 'hmh: = hmac.New (sha256.New, hmk)', поэтому мне нужно их импортировать. – Intermernet

+0

Почему вы используете протокол HMAC? – Luke

ответ

5

Вы, кажется, изменили аргументы на hash() в одной из своих функций. В Check(), у вас есть:

hchk, err := hash(hmk, pw, s) 

В то время как в New() у вас есть:

h, err = hash(pw, hmk, s) 

Это, очевидно, не будет производить тот же результат, приводящий к ошибке проверки.

С тремя аналогичными аргументами с такими же типами подобные ошибки не слишком удивительны. Возможно, было бы интересно посмотреть, можете ли вы реструктурировать вещи, чтобы система типов могла распознать этот класс ошибок?

+0

Спасибо за это, теперь это так очевидно, что это смущает! Я отметил как правильный ответ, но у меня нет достаточного количества голосов, чтобы перестраховать вас. Извините, если бы я мог! Я смотрел этот код часами и продолжал смотреть на очевидное! – Intermernet

 Смежные вопросы

  • Нет связанных вопросов^_^