go-mockid/xkeypairs/generate.go

70 lines
1.8 KiB
Go

package xkeypairs
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"io"
"log"
mathrand "math/rand"
"git.rootprojects.org/root/keypairs"
)
const maxRetry = 16
// RandomReader may be overwritten for testing
var RandomReader io.Reader = rand.Reader
//var RandomReader = rand.Reader
// KeyOptions are the things that we may need to know about a request to fulfill it properly
type KeyOptions struct {
Key string `json:"key"`
KeyType string `json:"kty"`
Seed int64 `json:"-"`
SeedStr string `json:"seed"`
Claims keypairs.Object `json:"claims"`
Header keypairs.Object `json:"header"`
}
// this shananigans is only for testing and debug API stuff
func (o *KeyOptions) MyFooNextReader() io.Reader {
if 0 == o.Seed {
return RandomReader
}
return mathrand.New(mathrand.NewSource(o.Seed))
}
// GenPrivKey generates a 256-bit entropy RSA or ECDSA private key
func GenPrivKey(opts *KeyOptions) keypairs.PrivateKey {
var privkey keypairs.PrivateKey
if "RSA" == opts.KeyType {
keylen := 2048
privkey, _ = rsa.GenerateKey(opts.MyFooNextReader(), keylen)
if 0 != opts.Seed {
for i := 0; i < maxRetry; i++ {
otherkey, _ := rsa.GenerateKey(opts.MyFooNextReader(), keylen)
otherCmp := otherkey.D.Cmp(privkey.(*rsa.PrivateKey).D)
if 0 != otherCmp {
// There are two possible keys, choose the lesser D value
// See https://github.com/square/go-jose/issues/189
if otherCmp < 0 {
privkey = otherkey
}
break
}
if maxRetry == i-1 {
log.Printf("error: coinflip landed on heads %d times", maxRetry)
}
}
}
} else {
// TODO: EC keys may also suffer the same random problems in the future
privkey, _ = ecdsa.GenerateKey(elliptic.P256(), opts.MyFooNextReader())
}
return privkey
}