Files
did-it/crypto/rsa/private.go

177 lines
4.5 KiB
Go

package rsa
import (
stdcrypto "crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"math/big"
"github.com/ucan-wg/go-varsig"
"code.sonr.org/go/did-it/crypto"
)
var _ crypto.PrivateKeySigningASN1 = &PrivateKey{}
type PrivateKey struct {
k *rsa.PrivateKey
}
func PrivateKeyFromNEDPQ(n, e, d, p, q []byte) (*PrivateKey, error) {
pub, err := PublicKeyFromNE(n, e)
if err != nil {
return nil, err
}
dBInt := new(big.Int).SetBytes(d)
pBInt := new(big.Int).SetBytes(p)
qBInt := new(big.Int).SetBytes(q)
priv := &rsa.PrivateKey{
PublicKey: *pub.k,
D: dBInt,
Primes: []*big.Int{pBInt, qBInt},
}
err = priv.Validate()
if err != nil {
return nil, err
}
priv.Precompute()
return &PrivateKey{k: priv}, nil
}
// PrivateKeyFromPKCS8DER decodes a PKCS#8 DER (binary) encoded private key.
func PrivateKeyFromPKCS8DER(bytes []byte) (*PrivateKey, error) {
priv, err := x509.ParsePKCS8PrivateKey(bytes)
if err != nil {
return nil, err
}
rsaPriv, ok := priv.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("invalid private key type")
}
return &PrivateKey{k: rsaPriv}, nil
}
// PrivateKeyFromPKCS8PEM decodes an PKCS#8 PEM (string) encoded private key.
func PrivateKeyFromPKCS8PEM(str string) (*PrivateKey, error) {
block, _ := pem.Decode([]byte(str))
if block == nil {
return nil, fmt.Errorf("failed to decode PEM block")
}
if block.Type != pemPrivBlockType {
return nil, fmt.Errorf("incorrect PEM block type")
}
return PrivateKeyFromPKCS8DER(block.Bytes)
}
func (p *PrivateKey) KeyLength() uint64 {
return uint64((p.k.N.BitLen() + 7) / 8) // Round up to the nearest byte
}
func (p *PrivateKey) DBytes() []byte {
byteLength := (p.k.D.BitLen() + 7) / 8 // Round up to the nearest byte
buf := make([]byte, byteLength)
p.k.D.FillBytes(buf)
return buf
}
func (p *PrivateKey) PBytes() []byte {
byteLength := (p.k.Primes[0].BitLen() + 7) / 8 // Round up to the nearest byte
buf := make([]byte, byteLength)
p.k.Primes[0].FillBytes(buf)
return buf
}
func (p *PrivateKey) QBytes() []byte {
byteLength := (p.k.Primes[1].BitLen() + 7) / 8 // Round up to the nearest byte
buf := make([]byte, byteLength)
p.k.Primes[1].FillBytes(buf)
return buf
}
func (p *PrivateKey) DpBytes() []byte {
if p.k.Precomputed.Dp == nil {
p.k.Precompute()
}
byteLength := (p.k.Precomputed.Dp.BitLen() + 7) / 8 // Round up to the nearest byte
buf := make([]byte, byteLength)
p.k.Precomputed.Dp.FillBytes(buf)
return buf
}
func (p *PrivateKey) DqBytes() []byte {
if p.k.Precomputed.Dq == nil {
p.k.Precompute()
}
byteLength := (p.k.Precomputed.Dq.BitLen() + 7) / 8 // Round up to the nearest byte
buf := make([]byte, byteLength)
p.k.Precomputed.Dq.FillBytes(buf)
return buf
}
func (p *PrivateKey) QiBytes() []byte {
if p.k.Precomputed.Qinv == nil {
p.k.Precompute()
}
byteLength := (p.k.Precomputed.Qinv.BitLen() + 7) / 8 // Round up to the nearest byte
buf := make([]byte, byteLength)
p.k.Precomputed.Qinv.FillBytes(buf)
return buf
}
func (p *PrivateKey) Equal(other crypto.PrivateKey) bool {
if other, ok := other.(*PrivateKey); ok {
return p.k.Equal(other.k)
}
return false
}
func (p *PrivateKey) Public() crypto.PublicKey {
rsaPub := p.k.Public().(*rsa.PublicKey)
return &PublicKey{k: rsaPub}
}
func (p *PrivateKey) ToPKCS8DER() []byte {
res, _ := x509.MarshalPKCS8PrivateKey(p.k)
return res
}
func (p *PrivateKey) ToPKCS8PEM() string {
der := p.ToPKCS8DER()
return string(pem.EncodeToMemory(&pem.Block{
Type: pemPrivBlockType,
Bytes: der,
}))
}
// The default signing hash is:
// - SHA-256 for keys of length 2048 bits and under
// - SHA-384 for keys of length 3072 bits and under
// - SHA-512 for higher key length
func (p *PrivateKey) Varsig(opts ...crypto.SigningOption) varsig.Varsig {
params := crypto.CollectSigningOptions(opts)
hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen()))
return varsig.NewRSAVarsig(hashCode.ToVarsigHash(), uint64(p.KeyLength()), params.PayloadEncoding())
}
// SignToASN1 produce a PKCS#1 v1.5 signature.
// The default signing hash is:
// - SHA-256 for keys of length 2048 bits and under
// - SHA-384 for keys of length 3072 bits and under
// - SHA-512 for higher key length
func (p *PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
params := crypto.CollectSigningOptions(opts)
hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen()))
hasher := hashCode.New()
hasher.Write(message)
hash := hasher.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, p.k, stdcrypto.Hash(hashCode), hash)
}