mirror of https://github.com/portainer/portainer
				
				
				
			feat(libcrypto): move into the Portainer repository EE-5476 (#10230)
							parent
							
								
									9a234204fa
								
							
						
					
					
						commit
						090fa4aeb3
					
				| 
						 | 
				
			
			@ -8,9 +8,9 @@ import (
 | 
			
		|||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/portainer/libcrypto"
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/edge/cache"
 | 
			
		||||
	"github.com/portainer/portainer/pkg/libcrypto"
 | 
			
		||||
 | 
			
		||||
	"github.com/dchest/uniuri"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ import (
 | 
			
		|||
	"encoding/base64"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
 | 
			
		||||
	"github.com/portainer/libcrypto"
 | 
			
		||||
	"github.com/portainer/portainer/pkg/libcrypto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,10 +5,10 @@ import (
 | 
			
		|||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/portainer/libcrypto"
 | 
			
		||||
	"github.com/portainer/libhttp/response"
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/client"
 | 
			
		||||
	"github.com/portainer/portainer/pkg/libcrypto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type motdResponse struct {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,9 +6,9 @@ import (
 | 
			
		|||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/portainer/libcrypto"
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
	"github.com/portainer/portainer/pkg/libcrypto"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/rs/zerolog/log"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										1
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -37,7 +37,6 @@ require (
 | 
			
		|||
	github.com/orcaman/concurrent-map v1.0.0
 | 
			
		||||
	github.com/patrickmn/go-cache v2.1.0+incompatible
 | 
			
		||||
	github.com/pkg/errors v0.9.1
 | 
			
		||||
	github.com/portainer/libcrypto v0.0.0-20220506221303-1f4fb3b30f9a
 | 
			
		||||
	github.com/portainer/libhttp v0.0.0-20230615144939-a999f666d9a9
 | 
			
		||||
	github.com/robfig/cron/v3 v3.0.1
 | 
			
		||||
	github.com/rs/zerolog v1.29.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										2
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -311,8 +311,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 | 
			
		|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
github.com/portainer/libcrypto v0.0.0-20220506221303-1f4fb3b30f9a h1:B0z3skIMT+OwVNJPQhKp52X+9OWW6A9n5UWig3lHBJk=
 | 
			
		||||
github.com/portainer/libcrypto v0.0.0-20220506221303-1f4fb3b30f9a/go.mod h1:n54EEIq+MM0NNtqLeCby8ljL+l275VpolXO0ibHegLE=
 | 
			
		||||
github.com/portainer/libhttp v0.0.0-20230615144939-a999f666d9a9 h1:Jq8g/pDcFL1Z/DnZgn6DyaWu29y9+RiB5aOJ/Xw4960=
 | 
			
		||||
github.com/portainer/libhttp v0.0.0-20230615144939-a999f666d9a9/go.mod h1:H49JLiywwLt2rrJVroafEWy8fIs0i7mThAThK40sbb8=
 | 
			
		||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
Copyright (c) 2018-2020 Portainer.io
 | 
			
		||||
 | 
			
		||||
This software is provided 'as-is', without any express or implied
 | 
			
		||||
warranty.  In no event will the authors be held liable for any damages
 | 
			
		||||
arising from the use of this software.
 | 
			
		||||
 | 
			
		||||
Permission is granted to anyone to use this software for any purpose,
 | 
			
		||||
including commercial applications, and to alter it and redistribute it
 | 
			
		||||
freely, subject to the following restrictions:
 | 
			
		||||
 | 
			
		||||
1. The origin of this software must not be misrepresented; you must not
 | 
			
		||||
   claim that you wrote the original software. If you use this software
 | 
			
		||||
   in a product, an acknowledgment in the product documentation would be
 | 
			
		||||
   appreciated but is not required.
 | 
			
		||||
2. Altered source versions must be plainly marked as such, and must not be
 | 
			
		||||
   misrepresented as being the original software.
 | 
			
		||||
3. This notice may not be removed or altered from any source distribution.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
# libcrypto
 | 
			
		||||
 | 
			
		||||
A small library providing encryption and decryption functions.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
package libcrypto
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/aes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Decrypt decrypts data using 256-bit AES-GCM.  This both hides the content of
 | 
			
		||||
// the data and provides a check that it hasn't been altered. Expects input
 | 
			
		||||
// form nonce|ciphertext|tag where '|' indicates concatenation.
 | 
			
		||||
// Creates a 32bit hash of the key before decrypting the data.
 | 
			
		||||
func Decrypt(data []byte, key []byte) ([]byte, error) {
 | 
			
		||||
	hashKey := Hash32Bit(key)
 | 
			
		||||
 | 
			
		||||
	block, err := aes.NewCipher(hashKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gcm, err := cipher.NewGCM(block)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(data) < gcm.NonceSize() {
 | 
			
		||||
		return nil, errors.New("malformed ciphertext")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return gcm.Open(nil,
 | 
			
		||||
		data[:gcm.NonceSize()],
 | 
			
		||||
		data[gcm.NonceSize():],
 | 
			
		||||
		nil,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
package libcrypto
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/aes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Encrypt encrypts data using 256-bit AES-GCM.  This both hides the content of
 | 
			
		||||
// the data and provides a check that it hasn't been altered. Output takes the
 | 
			
		||||
// form nonce|ciphertext|tag where '|' indicates concatenation.
 | 
			
		||||
// Creates a 32bit hash of the key before encrypting the data.
 | 
			
		||||
func Encrypt(data, key []byte) ([]byte, error) {
 | 
			
		||||
	hashKey := Hash32Bit(key)
 | 
			
		||||
 | 
			
		||||
	block, err := aes.NewCipher(hashKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gcm, err := cipher.NewGCM(block)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nonce := make([]byte, gcm.NonceSize())
 | 
			
		||||
	_, err = io.ReadFull(rand.Reader, nonce)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return gcm.Seal(nonce, nonce, data, nil), nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
package libcrypto
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HashFromBytes returns the hash of the specified data
 | 
			
		||||
func HashFromBytes(data []byte) []byte {
 | 
			
		||||
	digest := md5.New()
 | 
			
		||||
	digest.Write(data)
 | 
			
		||||
	return digest.Sum(nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hash32Bit returns a hexadecimal encoded hash
 | 
			
		||||
func Hash32Bit(data []byte) []byte {
 | 
			
		||||
	hash := HashFromBytes(data)
 | 
			
		||||
	return []byte(hex.EncodeToString(hash))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
package libcrypto
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GenerateCertsForHost generates a self-signed certificate for host and saves them at certPath and keyPath
 | 
			
		||||
func GenerateCertsForHost(hostname, ip, certPath, keyPath string, expiry time.Time) error {
 | 
			
		||||
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
 | 
			
		||||
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template := x509.Certificate{
 | 
			
		||||
		SerialNumber:          serialNumber,
 | 
			
		||||
		NotAfter:              expiry,
 | 
			
		||||
		NotBefore:             time.Now(),
 | 
			
		||||
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
 | 
			
		||||
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
 | 
			
		||||
		BasicConstraintsValid: true,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parsedIP := net.ParseIP(ip)
 | 
			
		||||
	if parsedIP == nil {
 | 
			
		||||
		return errors.New("Failed parsing host ip")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template.DNSNames = append(template.DNSNames, hostname)
 | 
			
		||||
	template.IPAddresses = append(template.IPAddresses, parsedIP)
 | 
			
		||||
 | 
			
		||||
	keyPair, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	encodedCert, err := x509.CreateCertificate(rand.Reader, &template, &template, &keyPair.PublicKey, keyPair)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = createPEMEncodedFile(certPath, "CERTIFICATE", encodedCert)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key, err := x509.MarshalECPrivateKey(keyPair)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = createPEMEncodedFile(keyPath, "EC PRIVATE KEY", key)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createPEMEncodedFile(path, header string, data []byte) error {
 | 
			
		||||
	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer file.Close()
 | 
			
		||||
 | 
			
		||||
	err = pem.Encode(file, &pem.Block{Type: header, Bytes: data})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue