cerrado @ 2e4b2fb52a539188b27212005d626f0849e78196

  1package service
  2
  3import (
  4	"bytes"
  5	"crypto/aes"
  6	"crypto/cipher"
  7	"crypto/rand"
  8	"encoding/base64"
  9	"fmt"
 10	"io"
 11
 12	"golang.org/x/crypto/bcrypt"
 13)
 14
 15type (
 16	AuthService struct {
 17		authRepository authRepository
 18	}
 19
 20	authRepository interface {
 21		GetPassphrase() []byte
 22		GetBase64AesKey() []byte
 23	}
 24)
 25
 26var tokenSeed = []byte("cerrado")
 27
 28func (a *AuthService) CheckAuth(username, password string) bool {
 29	passphrase := a.authRepository.GetPassphrase()
 30	pass := []byte(fmt.Sprintf("%s:%s", username, password))
 31
 32	err := bcrypt.CompareHashAndPassword(passphrase, pass)
 33
 34	return err == nil
 35}
 36
 37func (a *AuthService) IssueToken() ([]byte, error) {
 38	// TODO: do this block only once
 39	base := a.authRepository.GetBase64AesKey()
 40
 41	dbuf, err := base64.StdEncoding.DecodeString(string(base))
 42	if err != nil {
 43		return nil, err
 44	}
 45
 46	block, err := aes.NewCipher(dbuf)
 47	if err != nil {
 48		return nil, err
 49	}
 50
 51	gcm, err := cipher.NewGCM(block)
 52	if err != nil {
 53		return nil, err
 54	}
 55
 56	nonce := make([]byte, gcm.NonceSize())
 57	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
 58		return nil, err
 59	}
 60
 61	ciphertext := gcm.Seal(nonce, nonce, tokenSeed, nil)
 62
 63	return ciphertext, nil
 64}
 65
 66func (a *AuthService) ValidateToken(token []byte) (bool, error) {
 67	base := a.authRepository.GetBase64AesKey()
 68
 69	dbuf, err := base64.StdEncoding.DecodeString(string(base))
 70	if err != nil {
 71		return false, err
 72	}
 73
 74	block, err := aes.NewCipher(dbuf)
 75	if err != nil {
 76		return false, err
 77	}
 78
 79	gcm, err := cipher.NewGCM(block)
 80	if err != nil {
 81		return false, err
 82	}
 83
 84	nonceSize := gcm.NonceSize()
 85	if len(token) < nonceSize {
 86		return false, fmt.Errorf("ciphertext too short")
 87	}
 88
 89	nonce, ciphertext := token[:nonceSize], token[nonceSize:]
 90	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
 91	if err != nil {
 92		return false, err
 93	}
 94
 95	return bytes.Equal(tokenSeed, plaintext), nil
 96}
 97
 98func GenerateHash(username, password string) (string, error) {
 99	passphrase := fmt.Sprintf("%s:%s", username, password)
100	bytes, err := bcrypt.GenerateFromPassword([]byte(passphrase), 14)
101	if err != nil {
102		return "", err
103	}
104
105	return string(bytes), nil
106}
107
108func GenerateAesKey() (string, error) {
109	key := make([]byte, 32)
110
111	_, err := rand.Read(key)
112	if err != nil {
113		return "", err
114	}
115
116	return base64.StdEncoding.EncodeToString(key), nil
117}