mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(libcrypto): move into the Portainer repository EE-5476 (#10230)
This commit is contained in:
parent
9a234204fa
commit
090fa4aeb3
12 changed files with 194 additions and 7 deletions
17
pkg/libcrypto/LICENSE
Normal file
17
pkg/libcrypto/LICENSE
Normal file
|
@ -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.
|
3
pkg/libcrypto/README.md
Normal file
3
pkg/libcrypto/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# libcrypto
|
||||
|
||||
A small library providing encryption and decryption functions.
|
35
pkg/libcrypto/decrypt.go
Normal file
35
pkg/libcrypto/decrypt.go
Normal file
|
@ -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,
|
||||
)
|
||||
}
|
34
pkg/libcrypto/encrypt.go
Normal file
34
pkg/libcrypto/encrypt.go
Normal file
|
@ -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
|
||||
}
|
19
pkg/libcrypto/hash.go
Normal file
19
pkg/libcrypto/hash.go
Normal file
|
@ -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))
|
||||
}
|
82
pkg/libcrypto/ssl.go
Normal file
82
pkg/libcrypto/ssl.go
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue