safing-jess/tools/gostdlib/rsa-keys.go

213 lines
4.6 KiB
Go

package gostdlib
import (
"crypto"
"crypto/rsa"
"crypto/x509"
"fmt"
"math/big"
"github.com/safing/jess/tools"
"github.com/safing/structures/container"
)
type rsaBase struct {
tools.ToolLogicBase
}
// LoadKey implements the ToolLogic interface.
func (base *rsaBase) LoadKey(signet tools.SignetInt) error {
var pubKey crypto.PublicKey
var privKey *rsa.PrivateKey
key, public := signet.GetStoredKey()
c := container.New(key)
// check serialization version
version, err := c.GetNextN8()
if err != nil || version != 1 {
return tools.ErrInvalidKey
}
// load key
if public {
pubKey, err = x509.ParsePKCS1PublicKey(c.CompileData())
} else {
privKey, err = x509.ParsePKCS1PrivateKey(c.CompileData())
if err != nil {
return tools.ErrInvalidKey
}
// check and assign keys
err = privKey.Validate()
if err == nil {
pubKey = privKey.Public()
}
}
// check for error
if err != nil {
return tools.ErrInvalidKey
}
signet.SetLoadedKeys(pubKey, privKey)
return nil
}
// StoreKey implements the ToolLogic interface.
func (base *rsaBase) StoreKey(signet tools.SignetInt) error {
pubKey := signet.PublicKey()
privKey := signet.PrivateKey()
public := privKey == nil
// create storage with serialization version
c := container.New()
c.AppendNumber(1)
// store keys
if public {
rsaPubKey, ok := pubKey.(*rsa.PublicKey)
if !ok {
return tools.ErrInvalidKey
}
c.Append(x509.MarshalPKCS1PublicKey(rsaPubKey))
} else {
rsaPrivKey, ok := privKey.(*rsa.PrivateKey)
if !ok {
return tools.ErrInvalidKey
}
c.Append(x509.MarshalPKCS1PrivateKey(rsaPrivKey))
}
signet.SetStoredKey(c.CompileData(), public)
return nil
}
// GenerateKey implements the ToolLogic interface.
func (base *rsaBase) GenerateKey(signet tools.SignetInt) error {
// get key size
keySize := getRSAKeySizeBySecurityLevel(base.Helper().MaxSecurityLevel())
if keySize < 0 {
return fmt.Errorf("invalid security level of %d for rsa key - rsa based cryptography is only available for levels 112 to 256 (recommended only up to 192)", base.Helper().MaxSecurityLevel())
}
// generate new private key
privKey, err := rsa.GenerateKey(base.Helper().Random(), keySize)
if err != nil {
return err
}
// get public key
pubKey := privKey.Public()
signet.SetLoadedKeys(pubKey, privKey)
return nil
}
// BurnKey implements the ToolLogic interface. This is currently ineffective, see known issues in the project's README.
func (base *rsaBase) BurnKey(signet tools.SignetInt) error {
pubKey := signet.PublicKey()
privKey := signet.PrivateKey()
// burn public key
if pubKey != nil {
rsaPubKey, ok := pubKey.(*rsa.PublicKey)
if ok && rsaPubKey != nil {
rsaPubKey.E = 0
burnBigInt(rsaPubKey.N)
}
}
// burn private key
if privKey != nil {
rsaPrivKey, ok := privKey.(*rsa.PrivateKey)
if ok && rsaPrivKey != nil {
// private key
burnBigInt(rsaPrivKey.D)
for _, bigInt := range rsaPrivKey.Primes {
burnBigInt(bigInt)
}
// precomputed values
burnBigInt(rsaPrivKey.Precomputed.Dp)
burnBigInt(rsaPrivKey.Precomputed.Dq)
burnBigInt(rsaPrivKey.Precomputed.Qinv)
for _, crtVal := range rsaPrivKey.Precomputed.CRTValues {
burnBigInt(crtVal.Coeff)
burnBigInt(crtVal.Exp)
burnBigInt(crtVal.R)
}
// public key
rsaPrivKey.PublicKey.E = 0
burnBigInt(rsaPrivKey.PublicKey.N)
}
}
return nil
}
var zeroBigInt = big.NewInt(0)
func burnBigInt(i *big.Int) {
if i != nil {
i.Set(zeroBigInt)
}
}
// SecurityLevel implements the ToolLogic interface.
func (base *rsaBase) SecurityLevel(signet tools.SignetInt) (int, error) {
if signet == nil {
return 0, nil
}
pubkey := signet.PublicKey()
if pubkey == nil {
err := signet.LoadKey()
if err != nil {
return 0, fmt.Errorf("failed to load key to calculate security level: %w", err)
}
pubkey = signet.PublicKey()
}
rsaPubKey, ok := pubkey.(*rsa.PublicKey)
if !ok {
return 0, tools.ErrInvalidKey
}
level := getSecurityLevelByRSAKeySize(rsaPubKey.Size() * 8)
if level < 0 {
return 0, fmt.Errorf("rsa key is too small (%d bits) and can be broken trivially", rsaPubKey.Size()*8)
}
return level, nil
}
func getRSAKeySizeBySecurityLevel(level int) (keySize int) {
switch {
case level <= 112:
return 2048
case level <= 128:
return 3072
case level <= 192:
return 7680
case level <= 256:
return 15360
default:
return 256 // max level for rsa
}
}
func getSecurityLevelByRSAKeySize(keySize int) (level int) {
switch {
case keySize >= 15360:
return 256
case keySize >= 7680:
return 192
case keySize >= 3072:
return 128
case keySize >= 2048:
return 112
case keySize >= 1024:
return 80
case keySize >= 512:
return 56
default:
return -1 // error
}
}