Files
paralus/pkg/sentry/cryptoutil/key.go
nirav-rafay c66bdc25cd restructure rcloud-base as a single base controller (#37)
* restructure rcloud-base as a single base controller
* updated master.rest
* moved sentry from internal to pkg as it is used by relay
* removing unused rpc and it's dependencies
* Fix usermgmt tests
* Don't redefine variables in rest file
Co-authored-by: Abin Simon <abin.simon@rafay.co>
2022-03-03 17:59:06 +05:30

142 lines
3.0 KiB
Go

package cryptoutil
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
)
const (
ecKeyType = "EC PRIVATE KEY"
rsaKeyType = "RSA PRIVATE KEY"
)
// PasswordFunc is the signature for passing password while
// PEM encoding/decoding private keys
type PasswordFunc func() ([]byte, error)
// NoPassword should be used when the private key need not be encrypted
var NoPassword = func() ([]byte, error) {
return nil, nil
}
// EncodePrivateKey PEM encodes private key
// when password is not empty private key is encrypted with password
func EncodePrivateKey(privKey crypto.PrivateKey, f PasswordFunc) ([]byte, error) {
password, err := f()
if err != nil {
return nil, fmt.Errorf("unable to get password %s", err.Error())
}
switch privKey.(type) {
case *ecdsa.PrivateKey:
ecPrivKey := privKey.(*ecdsa.PrivateKey)
b, err := x509.MarshalECPrivateKey(ecPrivKey)
if err != nil {
return nil, err
}
var p *pem.Block
if len(password) == 0 {
p = &pem.Block{
Type: ecKeyType,
Bytes: b,
}
} else {
p, err = x509.EncryptPEMBlock(rand.Reader, ecKeyType, b, password, x509.PEMCipherAES256)
if err != nil {
return nil, err
}
}
return pem.EncodeToMemory(p), nil
case *rsa.PrivateKey:
rsaPrivKey := privKey.(*rsa.PrivateKey)
b := x509.MarshalPKCS1PrivateKey(rsaPrivKey)
var p *pem.Block
if len(password) == 0 {
p = &pem.Block{
Type: rsaKeyType,
Bytes: b,
}
} else {
p, err = x509.EncryptPEMBlock(rand.Reader, rsaKeyType, b, password, x509.PEMCipherAES256)
if err != nil {
return nil, err
}
}
return pem.EncodeToMemory(p), nil
default:
return nil, fmt.Errorf("unsupported private key %T", privKey)
}
}
// DecodePrivateKey decodes PEM encoded private key
// when PasswordFunc is provied private key is decrypted with password
func DecodePrivateKey(privKey []byte, f PasswordFunc) (crypto.PrivateKey, error) {
p, err := decodePEM(privKey)
if err != nil {
return nil, err
}
password, err := f()
if err != nil {
return nil, err
}
var b []byte
switch {
case x509.IsEncryptedPEMBlock(p):
b, err = x509.DecryptPEMBlock(p, password)
if err != nil {
fmt.Print("DecryptPEMBlock here is the error", err.Error())
return nil, err
}
default:
b = p.Bytes
}
fmt.Print("p.Type", p.Type)
switch p.Type {
case ecKeyType:
return x509.ParseECPrivateKey(b)
case rsaKeyType:
return x509.ParsePKCS1PrivateKey(b)
default:
return nil, fmt.Errorf("type %s is not suported", p.Type)
}
}
// DecryptPrivateKeyAsPem returns a decrypted private key in PEM encoding
func DecryptPrivateKeyAsPem(privKey []byte, f PasswordFunc) ([]byte, error) {
pk, err := DecodePrivateKey(privKey, f)
if err != nil {
return nil, err
}
return EncodePrivateKey(pk, NoPassword)
}
// GenerateECDSAPrivateKey generates new ECDSA private key
func GenerateECDSAPrivateKey() (*ecdsa.PrivateKey, error) {
ecKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
return ecKey, err
}