77 lines
1.8 KiB
Go
77 lines
1.8 KiB
Go
package vault
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/aes"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
// Tunable params for newly generated passwords.
|
|
var (
|
|
// bcrypt hash cost. The higher, the longer it takes to derive a password.
|
|
// Helps protect the hashes against brute force attacks.
|
|
HashCost = 14
|
|
)
|
|
|
|
// GenerateHash generates a bcrypt hash (slow) of a password, and then returns
|
|
// a SHA-256 sum of the hash.
|
|
func GenerateHash(password string) ([]byte, error) {
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), HashCost)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Make it a SHA-256 hash for easy use with AES-256.
|
|
hasher := sha256.New()
|
|
_, err = hasher.Write(hash)
|
|
bin := hasher.Sum(nil)
|
|
return bin, err
|
|
}
|
|
|
|
// HashToFilename converts a bcrypt hash into a safe filename on disk.
|
|
//
|
|
// It takes a SHA-256 sum of the hash and then splits it into a short tree
|
|
// for filesystem efficiency.
|
|
func HashToFilename(hash []byte) string {
|
|
sha := hex.EncodeToString(hash)
|
|
|
|
// Split it into a path tree.
|
|
var (
|
|
p1 = sha[:2]
|
|
p2 = sha[2:20]
|
|
p3 = sha[20:40]
|
|
p4 = sha[40:]
|
|
)
|
|
filename := strings.Join([]string{p1, p2, p3, p4}, "/")
|
|
return filename
|
|
}
|
|
|
|
// Encrypt data using AES-256.
|
|
func Encrypt(key []byte, data []byte) ([]byte, error) {
|
|
// Initialize an AES cipher.
|
|
encryptor, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Encrypt: aes.NewCipher error: %s", err)
|
|
}
|
|
|
|
// Pad the plaintext until it's a multiple of the AES block size.
|
|
buf := bytes.NewBuffer(data)
|
|
for buf.Len()%aes.BlockSize != 0 {
|
|
buf.WriteByte(' ')
|
|
}
|
|
Log.Info("data: %+v", data)
|
|
Log.Info("buf: %+v", buf.Bytes())
|
|
|
|
// Encode the data to ciphertext.
|
|
ciphertext := make([]byte, aes.BlockSize+buf.Len())
|
|
encryptor.Encrypt(ciphertext, buf.Bytes())
|
|
|
|
fmt.Printf("cipher: %+v\n", ciphertext)
|
|
return ciphertext, nil
|
|
}
|