// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package bcrypt_pbkdf implements bcrypt_pbkdf(3) from OpenBSD. // // See https://flak.tedunangst.com/post/bcrypt-pbkdf and // https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libutil/bcrypt_pbkdf.c.
package bcrypt_pbkdf import ( ) const blockSize = 32 // Key derives a key from the password, salt and rounds count, returning a // []byte of length keyLen that can be used as cryptographic key. func (, []byte, , int) ([]byte, error) { if < 1 { return nil, errors.New("bcrypt_pbkdf: number of rounds is too small") } if len() == 0 { return nil, errors.New("bcrypt_pbkdf: empty password") } if len() == 0 || len() > 1<<20 { return nil, errors.New("bcrypt_pbkdf: bad salt length") } if > 1024 { return nil, errors.New("bcrypt_pbkdf: keyLen is too large") } := ( + blockSize - 1) / blockSize := make([]byte, *blockSize) := sha512.New() .Write() := .Sum(nil) := make([]byte, 0, sha512.Size) , := make([]byte, 4), make([]byte, blockSize) for := 1; <= ; ++ { .Reset() .Write() [0] = byte( >> 24) [1] = byte( >> 16) [2] = byte( >> 8) [3] = byte() .Write() bcryptHash(, , .Sum()) := make([]byte, blockSize) copy(, ) for := 2; <= ; ++ { .Reset() .Write() bcryptHash(, , .Sum()) for := 0; < len(); ++ { [] ^= [] } } for , := range { [*+(-1)] = } } return [:], nil } var magic = []byte("OxychromaticBlowfishSwatDynamite") func bcryptHash(, , []byte) { , := blowfish.NewSaltedCipher(, ) if != nil { panic() } for := 0; < 64; ++ { blowfish.ExpandKey(, ) blowfish.ExpandKey(, ) } copy(, magic) for := 0; < 32; += 8 { for := 0; < 64; ++ { .Encrypt([:+8], [:+8]) } } // Swap bytes due to different endianness. for := 0; < 32; += 4 { [+3], [+2], [+1], [] = [], [+1], [+2], [+3] } }