123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- package sprig
- import (
- "bytes"
- "crypto/aes"
- "crypto/cipher"
- "crypto/dsa"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/hmac"
- "crypto/rand"
- "crypto/rsa"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/asn1"
- "encoding/base64"
- "encoding/binary"
- "encoding/hex"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- "hash/adler32"
- "math/big"
- "net"
- "time"
- "github.com/google/uuid"
- "golang.org/x/crypto/scrypt"
- )
- 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)
- }
- // uuidv4 provides a safe and secure UUID v4 implementation
- func uuidv4() string {
- return fmt.Sprintf("%s", uuid.New())
- }
- 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
- }
- }
- 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,
- )
- }
- decodedKey, _ := pem.Decode(key)
- if decodedKey == nil {
- return crt, errors.New("unable to decode key")
- }
- _, err = x509.ParsePKCS1PrivateKey(decodedKey.Bytes)
- if err != nil {
- return crt, fmt.Errorf(
- "error parsing prive key: decodedKey.Bytes: %s",
- err,
- )
- }
- crt.Cert = string(cert)
- crt.Key = string(key)
- return crt, nil
- }
- func generateCertificateAuthority(
- cn string,
- daysValid int,
- ) (certificate, error) {
- ca := certificate{}
- template, err := getBaseCertTemplate(cn, nil, nil, daysValid)
- if err != nil {
- return ca, err
- }
- // Override KeyUsage and IsCA
- template.KeyUsage = x509.KeyUsageKeyEncipherment |
- x509.KeyUsageDigitalSignature |
- x509.KeyUsageCertSign
- template.IsCA = true
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return ca, fmt.Errorf("error generating rsa key: %s", err)
- }
- ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv)
- if err != nil {
- return ca, err
- }
- return ca, nil
- }
- func generateSelfSignedCertificate(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- ) (certificate, error) {
- cert := certificate{}
- template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
- if err != nil {
- return cert, err
- }
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return cert, fmt.Errorf("error generating rsa key: %s", err)
- }
- cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv)
- if err != nil {
- return cert, err
- }
- return cert, nil
- }
- func generateSignedCertificate(
- cn string,
- ips []interface{},
- alternateDNS []interface{},
- daysValid int,
- ca certificate,
- ) (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,
- )
- }
- decodedSignerKey, _ := pem.Decode([]byte(ca.Key))
- if decodedSignerKey == nil {
- return cert, errors.New("unable to decode key")
- }
- signerKey, err := x509.ParsePKCS1PrivateKey(decodedSignerKey.Bytes)
- if err != nil {
- return cert, fmt.Errorf(
- "error parsing prive key: decodedSignerKey.Bytes: %s",
- err,
- )
- }
- template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
- if err != nil {
- return cert, err
- }
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return cert, fmt.Errorf("error generating rsa key: %s", err)
- }
- cert.Cert, cert.Key, err = getCertAndKey(
- template,
- priv,
- signerCert,
- signerKey,
- )
- if err != nil {
- return cert, err
- }
- return cert, nil
- }
- func getCertAndKey(
- template *x509.Certificate,
- signeeKey *rsa.PrivateKey,
- parent *x509.Certificate,
- signingKey *rsa.PrivateKey,
- ) (string, string, error) {
- derBytes, err := x509.CreateCertificate(
- rand.Reader,
- template,
- parent,
- &signeeKey.PublicKey,
- 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,
- &pem.Block{
- Type: "RSA PRIVATE KEY",
- Bytes: x509.MarshalPKCS1PrivateKey(signeeKey),
- },
- ); err != nil {
- return "", "", fmt.Errorf("error pem-encoding key: %s", err)
- }
- return string(certBuffer.Bytes()), string(keyBuffer.Bytes()), 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
- }
|