| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- package sprig
- import (
- "bytes"
- "crypto"
- "crypto/aes"
- "crypto/cipher"
- "crypto/dsa"
- "crypto/ecdsa"
- "crypto/ed25519"
- "crypto/elliptic"
- "crypto/hmac"
- "crypto/rand"
- "crypto/rsa"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/sha512"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/asn1"
- "encoding/base64"
- "encoding/binary"
- "encoding/hex"
- "encoding/pem"
- "errors"
- "fmt"
- "hash/adler32"
- "io"
- "math/big"
- "net"
- "strings"
- "time"
- "github.com/google/uuid"
- bcrypt_lib "golang.org/x/crypto/bcrypt"
- "golang.org/x/crypto/scrypt"
- )
- func sha512sum(input string) string {
- hash := sha512.Sum512([]byte(input))
- return hex.EncodeToString(hash[:])
- }
- func sha256sum(input string) string {
- hash := sha256.Sum256([]byte(input))
- return hex.EncodeToString(hash[:])
- }
- func sha1sum(input string) string {
- hash := sha1.Sum([]byte(input))
- return hex.EncodeToString(hash[:])
- }
- func adler32sum(input string) string {
- hash := adler32.Checksum([]byte(input))
- return fmt.Sprintf("%d", hash)
- }
- func bcrypt(input string) string {
- hash, err := bcrypt_lib.GenerateFromPassword([]byte(input), bcrypt_lib.DefaultCost)
- if err != nil {
- return fmt.Sprintf("failed to encrypt string with bcrypt: %s", err)
- }
- return string(hash)
- }
- func hashSha(password string) string {
- s := sha1.New()
- s.Write([]byte(password))
- passwordSum := []byte(s.Sum(nil))
- return base64.StdEncoding.EncodeToString(passwordSum)
- }
- type HashAlgorithm string
- const (
- HashBCrypt = "bcrypt"
- HashSHA = "sha"
- )
- func htpasswd(username string, password string, hashAlgorithm HashAlgorithm) string {
- if strings.Contains(username, ":") {
- return fmt.Sprintf("invalid username: %s", username)
- }
- switch hashAlgorithm {
- case HashSHA:
- return fmt.Sprintf("%s:{SHA}%s", username, hashSha(password))
- default:
- return fmt.Sprintf("%s:%s", username, bcrypt(password))
- }
- }
- func randBytes(count int) (string, error) {
- buf := make([]byte, count)
- if _, err := rand.Read(buf); err != nil {
- return "", err
- }
- return base64.StdEncoding.EncodeToString(buf), nil
- }
- func uuidv4() string {
- return uuid.New().String()
- }
- var masterPasswordSeed = "com.lyndir.masterpassword"
- var passwordTypeTemplates = 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 templateCharacters = map[byte]string{
- 'V': "AEIOU",
- 'C': "BCDFGHJKLMNPQRSTVWXYZ",
- 'v': "aeiou",
- 'c': "bcdfghjklmnpqrstvwxyz",
- 'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ",
- 'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz",
- 'n': "0123456789",
- 'o': "@&%?,=[]_:-+*$#!'^~;()/.",
- 'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()",
- }
- func derivePassword(counter uint32, passwordType, password, user, site string) string {
- var templates = passwordTypeTemplates[passwordType]
- if templates == nil {
- return fmt.Sprintf("cannot find password template %s", passwordType)
- }
- var buffer bytes.Buffer
- buffer.WriteString(masterPasswordSeed)
- 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(masterPasswordSeed))
- 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 {
- passChars := templateCharacters[element]
- passChar := passChars[int(seed[i+1])%len(passChars)]
- buffer.WriteByte(passChar)
- }
- return buffer.String()
- }
- func generatePrivateKey(typ string) string {
- var priv interface{}
- var err error
- switch typ {
- case "", "rsa":
- priv, err = rsa.GenerateKey(rand.Reader, 4096)
- case "dsa":
- key := new(dsa.PrivateKey)
- 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":
- priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- case "ed25519":
- _, priv, err = ed25519.GenerateKey(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:
- b, err := x509.MarshalPKCS8PrivateKey(k)
- if err != nil {
- return nil
- }
- return &pem.Block{Type: "PRIVATE KEY", Bytes: b}
- }
- }
- func parsePrivateKeyPEM(pemBlock string) (crypto.PrivateKey, error) {
- block, _ := pem.Decode([]byte(pemBlock))
- if block == nil {
- return nil, errors.New("no PEM data in input")
- }
- if block.Type == "PRIVATE KEY" {
- priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
- if err != nil {
- return nil, fmt.Errorf("decoding PEM as PKCS#8: %s", err)
- }
- return priv, nil
- } else if !strings.HasSuffix(block.Type, " PRIVATE KEY") {
- return nil, fmt.Errorf("no private key data in PEM block of type %s", block.Type)
- }
- switch block.Type[:len(block.Type)-12] {
- case "RSA":
- priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- return nil, fmt.Errorf("parsing RSA private key from PEM: %s", err)
- }
- return priv, nil
- case "EC":
- priv, err := x509.ParseECPrivateKey(block.Bytes)
- if err != nil {
- return nil, fmt.Errorf("parsing EC private key from PEM: %s", err)
- }
- return priv, nil
- case "DSA":
- var k DSAKeyFormat
- _, err := asn1.Unmarshal(block.Bytes, &k)
- if err != nil {
- return nil, fmt.Errorf("parsing DSA private key from PEM: %s", err)
- }
- priv := &dsa.PrivateKey{
- PublicKey: dsa.PublicKey{
- Parameters: dsa.Parameters{
- P: k.P, Q: k.Q, G: k.G,
- },
- Y: k.Y,
- },
- X: k.X,
- }
- return priv, nil
- default:
- return nil, fmt.Errorf("invalid private key type %s", block.Type)
- }
- }
- func getPublicKey(priv crypto.PrivateKey) (crypto.PublicKey, error) {
- switch k := priv.(type) {
- case interface{ Public() crypto.PublicKey }:
- return k.Public(), nil
- case *dsa.PrivateKey:
- return &k.PublicKey, nil
- default:
- return nil, fmt.Errorf("unable to get public key for type %T", priv)
- }
- }
- type certificate struct {
- Cert string
- Key string
- }
- func buildCustomCertificate(b64cert string, b64key string) (certificate, error) {
- crt := certificate{}
- cert, err := base64.StdEncoding.DecodeString(b64cert)
- if err != nil {
- return crt, errors.New("unable to decode base64 certificate")
- }
- key, err := base64.StdEncoding.DecodeString(b64key)
- if err != nil {
- return crt, errors.New("unable to decode base64 private key")
- }
- decodedCert, _ := pem.Decode(cert)
- if decodedCert == nil {
- return crt, errors.New("unable to decode certificate")
- }
- _, err = x509.ParseCertificate(decodedCert.Bytes)
- if err != nil {
- return crt, fmt.Errorf(
- "error parsing certificate: decodedCert.Bytes: %s",
- err,
- )
- }
- _, err = parsePrivateKeyPEM(string(key))
- if err != nil {
- return crt, fmt.Errorf(
- "error parsing private key: %s",
- err,
- )
- }
- crt.Cert = string(cert)
- crt.Key = string(key)
- return crt, nil
- }
- func generateCertificateAuthority(
- cn string,
- daysValid int,
- ) (certificate, error) {
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
- }
- return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)
- }
- func generateCertificateAuthorityWithPEMKey(
- cn string,
- daysValid int,
- privPEM string,
- ) (certificate, error) {
- priv, err := parsePrivateKeyPEM(privPEM)
- if err != nil {
- return certificate{}, fmt.Errorf("parsing private key: %s", err)
- }
- return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)
- }
- func generateCertificateAuthorityWithKeyInternal(
- cn string,
- daysValid int,
- priv crypto.PrivateKey,
- ) (certificate, error) {
- ca := certificate{}
- template, err := getBaseCertTemplate(cn, nil, nil, daysValid)
- if err != nil {
- return ca, err
- }
- template.KeyUsage = x509.KeyUsageKeyEncipherment |
- x509.KeyUsageDigitalSignature |
- x509.KeyUsageCertSign
- template.IsCA = true
- ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv)
- return ca, err
- }
- func generateSelfSignedCertificate(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- ) (certificate, error) {
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
- }
- return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)
- }
- func generateSelfSignedCertificateWithPEMKey(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- privPEM string,
- ) (certificate, error) {
- priv, err := parsePrivateKeyPEM(privPEM)
- if err != nil {
- return certificate{}, fmt.Errorf("parsing private key: %s", err)
- }
- return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)
- }
- func generateSelfSignedCertificateWithKeyInternal(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- priv crypto.PrivateKey,
- ) (certificate, error) {
- cert := certificate{}
- template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
- if err != nil {
- return cert, err
- }
- cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv)
- return cert, err
- }
- func generateSignedCertificate(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- ca certificate,
- ) (certificate, error) {
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
- }
- return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)
- }
- func generateSignedCertificateWithPEMKey(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- ca certificate,
- privPEM string,
- ) (certificate, error) {
- priv, err := parsePrivateKeyPEM(privPEM)
- if err != nil {
- return certificate{}, fmt.Errorf("parsing private key: %s", err)
- }
- return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)
- }
- func generateSignedCertificateWithKeyInternal(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- ca certificate,
- priv crypto.PrivateKey,
- ) (certificate, error) {
- cert := certificate{}
- decodedSignerCert, _ := pem.Decode([]byte(ca.Cert))
- if decodedSignerCert == nil {
- return cert, errors.New("unable to decode certificate")
- }
- signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes)
- if err != nil {
- return cert, fmt.Errorf(
- "error parsing certificate: decodedSignerCert.Bytes: %s",
- err,
- )
- }
- signerKey, err := parsePrivateKeyPEM(ca.Key)
- if err != nil {
- return cert, fmt.Errorf(
- "error parsing private key: %s",
- err,
- )
- }
- template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
- if err != nil {
- return cert, err
- }
- cert.Cert, cert.Key, err = getCertAndKey(
- template,
- priv,
- signerCert,
- signerKey,
- )
- return cert, err
- }
- func getCertAndKey(
- template *x509.Certificate,
- signeeKey crypto.PrivateKey,
- parent *x509.Certificate,
- signingKey crypto.PrivateKey,
- ) (string, string, error) {
- signeePubKey, err := getPublicKey(signeeKey)
- if err != nil {
- return "", "", fmt.Errorf("error retrieving public key from signee key: %s", err)
- }
- derBytes, err := x509.CreateCertificate(
- rand.Reader,
- template,
- parent,
- signeePubKey,
- signingKey,
- )
- if err != nil {
- return "", "", fmt.Errorf("error creating certificate: %s", err)
- }
- certBuffer := bytes.Buffer{}
- if err := pem.Encode(
- &certBuffer,
- &pem.Block{Type: "CERTIFICATE", Bytes: derBytes},
- ); err != nil {
- return "", "", fmt.Errorf("error pem-encoding certificate: %s", err)
- }
- keyBuffer := bytes.Buffer{}
- if err := pem.Encode(
- &keyBuffer,
- pemBlockForKey(signeeKey),
- ); err != nil {
- return "", "", fmt.Errorf("error pem-encoding key: %s", err)
- }
- return certBuffer.String(), keyBuffer.String(), nil
- }
- func getBaseCertTemplate(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- ) (*x509.Certificate, error) {
- ipAddresses, err := getNetIPs(ips)
- if err != nil {
- return nil, err
- }
- dnsNames, err := getAlternateDNSStrs(alternateDNS)
- if err != nil {
- return nil, err
- }
- serialNumberUpperBound := new(big.Int).Lsh(big.NewInt(1), 128)
- serialNumber, err := rand.Int(rand.Reader, serialNumberUpperBound)
- if err != nil {
- return nil, err
- }
- return &x509.Certificate{
- SerialNumber: serialNumber,
- Subject: pkix.Name{
- CommonName: cn,
- },
- IPAddresses: ipAddresses,
- DNSNames: dnsNames,
- NotBefore: time.Now(),
- NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)),
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
- ExtKeyUsage: []x509.ExtKeyUsage{
- x509.ExtKeyUsageServerAuth,
- x509.ExtKeyUsageClientAuth,
- },
- BasicConstraintsValid: true,
- }, nil
- }
- func getNetIPs(ips []interface{}) ([]net.IP, error) {
- if ips == nil {
- return []net.IP{}, nil
- }
- var ipStr string
- var ok bool
- var netIP net.IP
- netIPs := make([]net.IP, len(ips))
- for i, ip := range ips {
- ipStr, ok = ip.(string)
- if !ok {
- return nil, fmt.Errorf("error parsing ip: %v is not a string", ip)
- }
- netIP = net.ParseIP(ipStr)
- if netIP == nil {
- return nil, fmt.Errorf("error parsing ip: %s", ipStr)
- }
- netIPs[i] = netIP
- }
- return netIPs, nil
- }
- func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) {
- if alternateDNS == nil {
- return []string{}, nil
- }
- var dnsStr string
- var ok bool
- alternateDNSStrs := make([]string, len(alternateDNS))
- for i, dns := range alternateDNS {
- dnsStr, ok = dns.(string)
- if !ok {
- return nil, fmt.Errorf(
- "error processing alternate dns name: %v is not a string",
- dns,
- )
- }
- alternateDNSStrs[i] = dnsStr
- }
- return alternateDNSStrs, nil
- }
- func encryptAES(password string, plaintext string) (string, error) {
- if plaintext == "" {
- return "", nil
- }
- key := make([]byte, 32)
- copy(key, []byte(password))
- block, err := aes.NewCipher(key)
- if err != nil {
- return "", err
- }
- content := []byte(plaintext)
- blockSize := block.BlockSize()
- padding := blockSize - len(content)%blockSize
- padtext := bytes.Repeat([]byte{byte(padding)}, padding)
- content = append(content, padtext...)
- ciphertext := make([]byte, aes.BlockSize+len(content))
- iv := ciphertext[:aes.BlockSize]
- if _, err := io.ReadFull(rand.Reader, iv); err != nil {
- return "", err
- }
- mode := cipher.NewCBCEncrypter(block, iv)
- mode.CryptBlocks(ciphertext[aes.BlockSize:], content)
- return base64.StdEncoding.EncodeToString(ciphertext), nil
- }
- func decryptAES(password string, crypt64 string) (string, error) {
- if crypt64 == "" {
- return "", nil
- }
- key := make([]byte, 32)
- copy(key, []byte(password))
- crypt, err := base64.StdEncoding.DecodeString(crypt64)
- if err != nil {
- return "", err
- }
- block, err := aes.NewCipher(key)
- if err != nil {
- return "", err
- }
- iv := crypt[:aes.BlockSize]
- crypt = crypt[aes.BlockSize:]
- decrypted := make([]byte, len(crypt))
- mode := cipher.NewCBCDecrypter(block, iv)
- mode.CryptBlocks(decrypted, crypt)
- return string(decrypted[:len(decrypted)-int(decrypted[len(decrypted)-1])]), nil
- }
|