177 lines
4.5 KiB
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)
|
|
}
|