package sprig import ( "bytes" "crypto/dsa" "crypto/ecdsa" "crypto/elliptic" "crypto/hmac" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/asn1" "encoding/binary" "encoding/hex" "encoding/pem" "fmt" "math/big" uuid "github.com/satori/go.uuid" "golang.org/x/crypto/scrypt" ) func sha256sum(input string) string { hash := sha256.Sum256([]byte(input)) return hex.EncodeToString(hash[:]) } // uuidv4 provides a safe and secure UUID v4 implementation func uuidv4() string { return fmt.Sprintf("%s", uuid.NewV4()) } var master_password_seed = "com.lyndir.masterpassword" var password_type_templates = map[string][][]byte{ "maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")}, "long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"), []byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"), []byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"), []byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"), []byte("CvccCvcvCvccno")}, "medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")}, "short": {[]byte("Cvcn")}, "basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")}, "pin": {[]byte("nnnn")}, } var template_characters = map[byte]string{ 'V': "AEIOU", 'C': "BCDFGHJKLMNPQRSTVWXYZ", 'v': "aeiou", 'c': "bcdfghjklmnpqrstvwxyz", 'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ", 'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz", 'n': "0123456789", 'o': "@&%?,=[]_:-+*$#!'^~;()/.", 'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()", } func derivePassword(counter uint32, password_type, password, user, site string) string { var templates = password_type_templates[password_type] if templates == nil { return fmt.Sprintf("cannot find password template %s", password_type) } var buffer bytes.Buffer buffer.WriteString(master_password_seed) binary.Write(&buffer, binary.BigEndian, uint32(len(user))) buffer.WriteString(user) salt := buffer.Bytes() key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64) if err != nil { return fmt.Sprintf("failed to derive password: %s", err) } buffer.Truncate(len(master_password_seed)) binary.Write(&buffer, binary.BigEndian, uint32(len(site))) buffer.WriteString(site) binary.Write(&buffer, binary.BigEndian, counter) var hmacv = hmac.New(sha256.New, key) hmacv.Write(buffer.Bytes()) var seed = hmacv.Sum(nil) var temp = templates[int(seed[0])%len(templates)] buffer.Truncate(0) for i, element := range temp { pass_chars := template_characters[element] pass_char := pass_chars[int(seed[i+1])%len(pass_chars)] buffer.WriteByte(pass_char) } return buffer.String() } func generatePrivateKey(typ string) string { var priv interface{} var err error switch typ { case "", "rsa": // good enough for government work priv, err = rsa.GenerateKey(rand.Reader, 4096) case "dsa": key := new(dsa.PrivateKey) // again, good enough for government work if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil { return fmt.Sprintf("failed to generate dsa params: %s", err) } err = dsa.GenerateKey(key, rand.Reader) priv = key case "ecdsa": // again, good enough for government work priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) default: return "Unknown type " + typ } if err != nil { return fmt.Sprintf("failed to generate private key: %s", err) } return string(pem.EncodeToMemory(pemBlockForKey(priv))) } type DSAKeyFormat struct { Version int P, Q, G, Y, X *big.Int } func pemBlockForKey(priv interface{}) *pem.Block { switch k := priv.(type) { case *rsa.PrivateKey: return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} case *dsa.PrivateKey: val := DSAKeyFormat{ P: k.P, Q: k.Q, G: k.G, Y: k.Y, X: k.X, } bytes, _ := asn1.Marshal(val) return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes} case *ecdsa.PrivateKey: b, _ := x509.MarshalECPrivateKey(k) return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} default: return nil } }