podman
653 строки · 16.2 Кб
1package sprig2
3import (4"bytes"5"crypto"6"crypto/aes"7"crypto/cipher"8"crypto/dsa"9"crypto/ecdsa"10"crypto/ed25519"11"crypto/elliptic"12"crypto/hmac"13"crypto/rand"14"crypto/rsa"15"crypto/sha1"16"crypto/sha256"17"crypto/x509"18"crypto/x509/pkix"19"encoding/asn1"20"encoding/base64"21"encoding/binary"22"encoding/hex"23"encoding/pem"24"errors"25"fmt"26"hash/adler32"27"io"28"math/big"29"net"30"time"31
32"strings"33
34"github.com/google/uuid"35bcrypt_lib "golang.org/x/crypto/bcrypt"36"golang.org/x/crypto/scrypt"37)
38
39func sha256sum(input string) string {40hash := sha256.Sum256([]byte(input))41return hex.EncodeToString(hash[:])42}
43
44func sha1sum(input string) string {45hash := sha1.Sum([]byte(input))46return hex.EncodeToString(hash[:])47}
48
49func adler32sum(input string) string {50hash := adler32.Checksum([]byte(input))51return fmt.Sprintf("%d", hash)52}
53
54func bcrypt(input string) string {55hash, err := bcrypt_lib.GenerateFromPassword([]byte(input), bcrypt_lib.DefaultCost)56if err != nil {57return fmt.Sprintf("failed to encrypt string with bcrypt: %s", err)58}59
60return string(hash)61}
62
63func htpasswd(username string, password string) string {64if strings.Contains(username, ":") {65return fmt.Sprintf("invalid username: %s", username)66}67return fmt.Sprintf("%s:%s", username, bcrypt(password))68}
69
70func randBytes(count int) (string, error) {71buf := make([]byte, count)72if _, err := rand.Read(buf); err != nil {73return "", err74}75return base64.StdEncoding.EncodeToString(buf), nil76}
77
78// uuidv4 provides a safe and secure UUID v4 implementation
79func uuidv4() string {80return uuid.New().String()81}
82
83var masterPasswordSeed = "com.lyndir.masterpassword"84
85var passwordTypeTemplates = map[string][][]byte{86"maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")},87"long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"),88[]byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"),89[]byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"),90[]byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"),91[]byte("CvccCvcvCvccno")},92"medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")},93"short": {[]byte("Cvcn")},94"basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")},95"pin": {[]byte("nnnn")},96}
97
98var templateCharacters = map[byte]string{99'V': "AEIOU",100'C': "BCDFGHJKLMNPQRSTVWXYZ",101'v': "aeiou",102'c': "bcdfghjklmnpqrstvwxyz",103'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ",104'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz",105'n': "0123456789",106'o': "@&%?,=[]_:-+*$#!'^~;()/.",107'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()",108}
109
110func derivePassword(counter uint32, passwordType, password, user, site string) string {111var templates = passwordTypeTemplates[passwordType]112if templates == nil {113return fmt.Sprintf("cannot find password template %s", passwordType)114}115
116var buffer bytes.Buffer117buffer.WriteString(masterPasswordSeed)118binary.Write(&buffer, binary.BigEndian, uint32(len(user)))119buffer.WriteString(user)120
121salt := buffer.Bytes()122key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64)123if err != nil {124return fmt.Sprintf("failed to derive password: %s", err)125}126
127buffer.Truncate(len(masterPasswordSeed))128binary.Write(&buffer, binary.BigEndian, uint32(len(site)))129buffer.WriteString(site)130binary.Write(&buffer, binary.BigEndian, counter)131
132var hmacv = hmac.New(sha256.New, key)133hmacv.Write(buffer.Bytes())134var seed = hmacv.Sum(nil)135var temp = templates[int(seed[0])%len(templates)]136
137buffer.Truncate(0)138for i, element := range temp {139passChars := templateCharacters[element]140passChar := passChars[int(seed[i+1])%len(passChars)]141buffer.WriteByte(passChar)142}143
144return buffer.String()145}
146
147func generatePrivateKey(typ string) string {148var priv interface{}149var err error150switch typ {151case "", "rsa":152// good enough for government work153priv, err = rsa.GenerateKey(rand.Reader, 4096)154case "dsa":155key := new(dsa.PrivateKey)156// again, good enough for government work157if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil {158return fmt.Sprintf("failed to generate dsa params: %s", err)159}160err = dsa.GenerateKey(key, rand.Reader)161priv = key162case "ecdsa":163// again, good enough for government work164priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)165case "ed25519":166_, priv, err = ed25519.GenerateKey(rand.Reader)167default:168return "Unknown type " + typ169}170if err != nil {171return fmt.Sprintf("failed to generate private key: %s", err)172}173
174return string(pem.EncodeToMemory(pemBlockForKey(priv)))175}
176
177// DSAKeyFormat stores the format for DSA keys.
178// Used by pemBlockForKey
179type DSAKeyFormat struct {180Version int181P, Q, G, Y, X *big.Int182}
183
184func pemBlockForKey(priv interface{}) *pem.Block {185switch k := priv.(type) {186case *rsa.PrivateKey:187return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}188case *dsa.PrivateKey:189val := DSAKeyFormat{190P: k.P, Q: k.Q, G: k.G,191Y: k.Y, X: k.X,192}193bytes, _ := asn1.Marshal(val)194return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes}195case *ecdsa.PrivateKey:196b, _ := x509.MarshalECPrivateKey(k)197return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}198default:199// attempt PKCS#8 format for all other keys200b, err := x509.MarshalPKCS8PrivateKey(k)201if err != nil {202return nil203}204return &pem.Block{Type: "PRIVATE KEY", Bytes: b}205}206}
207
208func parsePrivateKeyPEM(pemBlock string) (crypto.PrivateKey, error) {209block, _ := pem.Decode([]byte(pemBlock))210if block == nil {211return nil, errors.New("no PEM data in input")212}213
214if block.Type == "PRIVATE KEY" {215priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)216if err != nil {217return nil, fmt.Errorf("decoding PEM as PKCS#8: %s", err)218}219return priv, nil220} else if !strings.HasSuffix(block.Type, " PRIVATE KEY") {221return nil, fmt.Errorf("no private key data in PEM block of type %s", block.Type)222}223
224switch block.Type[:len(block.Type)-12] { // strip " PRIVATE KEY"225case "RSA":226priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)227if err != nil {228return nil, fmt.Errorf("parsing RSA private key from PEM: %s", err)229}230return priv, nil231case "EC":232priv, err := x509.ParseECPrivateKey(block.Bytes)233if err != nil {234return nil, fmt.Errorf("parsing EC private key from PEM: %s", err)235}236return priv, nil237case "DSA":238var k DSAKeyFormat239_, err := asn1.Unmarshal(block.Bytes, &k)240if err != nil {241return nil, fmt.Errorf("parsing DSA private key from PEM: %s", err)242}243priv := &dsa.PrivateKey{244PublicKey: dsa.PublicKey{245Parameters: dsa.Parameters{246P: k.P, Q: k.Q, G: k.G,247},248Y: k.Y,249},250X: k.X,251}252return priv, nil253default:254return nil, fmt.Errorf("invalid private key type %s", block.Type)255}256}
257
258func getPublicKey(priv crypto.PrivateKey) (crypto.PublicKey, error) {259switch k := priv.(type) {260case interface{ Public() crypto.PublicKey }:261return k.Public(), nil262case *dsa.PrivateKey:263return &k.PublicKey, nil264default:265return nil, fmt.Errorf("unable to get public key for type %T", priv)266}267}
268
269type certificate struct {270Cert string271Key string272}
273
274func buildCustomCertificate(b64cert string, b64key string) (certificate, error) {275crt := certificate{}276
277cert, err := base64.StdEncoding.DecodeString(b64cert)278if err != nil {279return crt, errors.New("unable to decode base64 certificate")280}281
282key, err := base64.StdEncoding.DecodeString(b64key)283if err != nil {284return crt, errors.New("unable to decode base64 private key")285}286
287decodedCert, _ := pem.Decode(cert)288if decodedCert == nil {289return crt, errors.New("unable to decode certificate")290}291_, err = x509.ParseCertificate(decodedCert.Bytes)292if err != nil {293return crt, fmt.Errorf(294"error parsing certificate: decodedCert.Bytes: %s",295err,296)297}298
299_, err = parsePrivateKeyPEM(string(key))300if err != nil {301return crt, fmt.Errorf(302"error parsing private key: %s",303err,304)305}306
307crt.Cert = string(cert)308crt.Key = string(key)309
310return crt, nil311}
312
313func generateCertificateAuthority(314cn string,315daysValid int,316) (certificate, error) {317priv, err := rsa.GenerateKey(rand.Reader, 2048)318if err != nil {319return certificate{}, fmt.Errorf("error generating rsa key: %s", err)320}321
322return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)323}
324
325func generateCertificateAuthorityWithPEMKey(326cn string,327daysValid int,328privPEM string,329) (certificate, error) {330priv, err := parsePrivateKeyPEM(privPEM)331if err != nil {332return certificate{}, fmt.Errorf("parsing private key: %s", err)333}334return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)335}
336
337func generateCertificateAuthorityWithKeyInternal(338cn string,339daysValid int,340priv crypto.PrivateKey,341) (certificate, error) {342ca := certificate{}343
344template, err := getBaseCertTemplate(cn, nil, nil, daysValid)345if err != nil {346return ca, err347}348// Override KeyUsage and IsCA349template.KeyUsage = x509.KeyUsageKeyEncipherment |350x509.KeyUsageDigitalSignature |351x509.KeyUsageCertSign352template.IsCA = true353
354ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv)355
356return ca, err357}
358
359func generateSelfSignedCertificate(360cn string,361ips []interface{},362alternateDNS []interface{},363daysValid int,364) (certificate, error) {365priv, err := rsa.GenerateKey(rand.Reader, 2048)366if err != nil {367return certificate{}, fmt.Errorf("error generating rsa key: %s", err)368}369return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)370}
371
372func generateSelfSignedCertificateWithPEMKey(373cn string,374ips []interface{},375alternateDNS []interface{},376daysValid int,377privPEM string,378) (certificate, error) {379priv, err := parsePrivateKeyPEM(privPEM)380if err != nil {381return certificate{}, fmt.Errorf("parsing private key: %s", err)382}383return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)384}
385
386func generateSelfSignedCertificateWithKeyInternal(387cn string,388ips []interface{},389alternateDNS []interface{},390daysValid int,391priv crypto.PrivateKey,392) (certificate, error) {393cert := certificate{}394
395template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)396if err != nil {397return cert, err398}399
400cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv)401
402return cert, err403}
404
405func generateSignedCertificate(406cn string,407ips []interface{},408alternateDNS []interface{},409daysValid int,410ca certificate,411) (certificate, error) {412priv, err := rsa.GenerateKey(rand.Reader, 2048)413if err != nil {414return certificate{}, fmt.Errorf("error generating rsa key: %s", err)415}416return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)417}
418
419func generateSignedCertificateWithPEMKey(420cn string,421ips []interface{},422alternateDNS []interface{},423daysValid int,424ca certificate,425privPEM string,426) (certificate, error) {427priv, err := parsePrivateKeyPEM(privPEM)428if err != nil {429return certificate{}, fmt.Errorf("parsing private key: %s", err)430}431return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)432}
433
434func generateSignedCertificateWithKeyInternal(435cn string,436ips []interface{},437alternateDNS []interface{},438daysValid int,439ca certificate,440priv crypto.PrivateKey,441) (certificate, error) {442cert := certificate{}443
444decodedSignerCert, _ := pem.Decode([]byte(ca.Cert))445if decodedSignerCert == nil {446return cert, errors.New("unable to decode certificate")447}448signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes)449if err != nil {450return cert, fmt.Errorf(451"error parsing certificate: decodedSignerCert.Bytes: %s",452err,453)454}455signerKey, err := parsePrivateKeyPEM(ca.Key)456if err != nil {457return cert, fmt.Errorf(458"error parsing private key: %s",459err,460)461}462
463template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)464if err != nil {465return cert, err466}467
468cert.Cert, cert.Key, err = getCertAndKey(469template,470priv,471signerCert,472signerKey,473)474
475return cert, err476}
477
478func getCertAndKey(479template *x509.Certificate,480signeeKey crypto.PrivateKey,481parent *x509.Certificate,482signingKey crypto.PrivateKey,483) (string, string, error) {484signeePubKey, err := getPublicKey(signeeKey)485if err != nil {486return "", "", fmt.Errorf("error retrieving public key from signee key: %s", err)487}488derBytes, err := x509.CreateCertificate(489rand.Reader,490template,491parent,492signeePubKey,493signingKey,494)495if err != nil {496return "", "", fmt.Errorf("error creating certificate: %s", err)497}498
499certBuffer := bytes.Buffer{}500if err := pem.Encode(501&certBuffer,502&pem.Block{Type: "CERTIFICATE", Bytes: derBytes},503); err != nil {504return "", "", fmt.Errorf("error pem-encoding certificate: %s", err)505}506
507keyBuffer := bytes.Buffer{}508if err := pem.Encode(509&keyBuffer,510pemBlockForKey(signeeKey),511); err != nil {512return "", "", fmt.Errorf("error pem-encoding key: %s", err)513}514
515return certBuffer.String(), keyBuffer.String(), nil516}
517
518func getBaseCertTemplate(519cn string,520ips []interface{},521alternateDNS []interface{},522daysValid int,523) (*x509.Certificate, error) {524ipAddresses, err := getNetIPs(ips)525if err != nil {526return nil, err527}528dnsNames, err := getAlternateDNSStrs(alternateDNS)529if err != nil {530return nil, err531}532serialNumberUpperBound := new(big.Int).Lsh(big.NewInt(1), 128)533serialNumber, err := rand.Int(rand.Reader, serialNumberUpperBound)534if err != nil {535return nil, err536}537return &x509.Certificate{538SerialNumber: serialNumber,539Subject: pkix.Name{540CommonName: cn,541},542IPAddresses: ipAddresses,543DNSNames: dnsNames,544NotBefore: time.Now(),545NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)),546KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,547ExtKeyUsage: []x509.ExtKeyUsage{548x509.ExtKeyUsageServerAuth,549x509.ExtKeyUsageClientAuth,550},551BasicConstraintsValid: true,552}, nil553}
554
555func getNetIPs(ips []interface{}) ([]net.IP, error) {556if ips == nil {557return []net.IP{}, nil558}559var ipStr string560var ok bool561var netIP net.IP562netIPs := make([]net.IP, len(ips))563for i, ip := range ips {564ipStr, ok = ip.(string)565if !ok {566return nil, fmt.Errorf("error parsing ip: %v is not a string", ip)567}568netIP = net.ParseIP(ipStr)569if netIP == nil {570return nil, fmt.Errorf("error parsing ip: %s", ipStr)571}572netIPs[i] = netIP573}574return netIPs, nil575}
576
577func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) {578if alternateDNS == nil {579return []string{}, nil580}581var dnsStr string582var ok bool583alternateDNSStrs := make([]string, len(alternateDNS))584for i, dns := range alternateDNS {585dnsStr, ok = dns.(string)586if !ok {587return nil, fmt.Errorf(588"error processing alternate dns name: %v is not a string",589dns,590)591}592alternateDNSStrs[i] = dnsStr593}594return alternateDNSStrs, nil595}
596
597func encryptAES(password string, plaintext string) (string, error) {598if plaintext == "" {599return "", nil600}601
602key := make([]byte, 32)603copy(key, []byte(password))604block, err := aes.NewCipher(key)605if err != nil {606return "", err607}608
609content := []byte(plaintext)610blockSize := block.BlockSize()611padding := blockSize - len(content)%blockSize612padtext := bytes.Repeat([]byte{byte(padding)}, padding)613content = append(content, padtext...)614
615ciphertext := make([]byte, aes.BlockSize+len(content))616
617iv := ciphertext[:aes.BlockSize]618if _, err := io.ReadFull(rand.Reader, iv); err != nil {619return "", err620}621
622mode := cipher.NewCBCEncrypter(block, iv)623mode.CryptBlocks(ciphertext[aes.BlockSize:], content)624
625return base64.StdEncoding.EncodeToString(ciphertext), nil626}
627
628func decryptAES(password string, crypt64 string) (string, error) {629if crypt64 == "" {630return "", nil631}632
633key := make([]byte, 32)634copy(key, []byte(password))635
636crypt, err := base64.StdEncoding.DecodeString(crypt64)637if err != nil {638return "", err639}640
641block, err := aes.NewCipher(key)642if err != nil {643return "", err644}645
646iv := crypt[:aes.BlockSize]647crypt = crypt[aes.BlockSize:]648decrypted := make([]byte, len(crypt))649mode := cipher.NewCBCDecrypter(block, iv)650mode.CryptBlocks(decrypted, crypt)651
652return string(decrypted[:len(decrypted)-int(decrypted[len(decrypted)-1])]), nil653}
654