package rsa
import (
)
type PublicKey struct {
N *bigmod.Modulus
E int
}
func ( *PublicKey) () int {
return (.N.BitLen() + 7) / 8
}
type PrivateKey struct {
pub PublicKey
d *bigmod.Nat
p, q *bigmod.Modulus
dP []byte
dQ []byte
qInv *bigmod.Nat
fipsApproved bool
}
func ( *PrivateKey) () *PublicKey {
return &.pub
}
func ( []byte, int, , , []byte) (*PrivateKey, error) {
, := bigmod.NewModulus()
if != nil {
return nil,
}
, := bigmod.NewModulus()
if != nil {
return nil,
}
, := bigmod.NewModulus()
if != nil {
return nil,
}
, := bigmod.NewNat().SetBytes(, )
if != nil {
return nil,
}
return newPrivateKey(, , , , )
}
func ( *bigmod.Modulus, int, *bigmod.Nat, , *bigmod.Modulus) (*PrivateKey, error) {
:= .Nat().SubOne()
, := bigmod.NewModulus(.Bytes())
if != nil {
return nil,
}
:= bigmod.NewNat().Mod(, ).Bytes()
:= .Nat().SubOne()
, := bigmod.NewModulus(.Bytes())
if != nil {
return nil,
}
:= bigmod.NewNat().Mod(, ).Bytes()
if .Nat().IsOdd() == 0 {
return nil, errors.New("crypto/rsa: p is even")
}
:= .Nat().SubOne().SubOne().Bytes()
:= bigmod.NewNat().Mod(.Nat(), )
.Exp(, , )
:= &PrivateKey{
pub: PublicKey{
N: , E: ,
},
d: , p: , q: ,
dP: , dQ: , qInv: ,
}
if := checkPrivateKey(); != nil {
return nil,
}
return , nil
}
func ( []byte, int, , , , , , []byte) (*PrivateKey, error) {
, := bigmod.NewModulus()
if != nil {
return nil,
}
, := bigmod.NewModulus()
if != nil {
return nil,
}
, := bigmod.NewModulus()
if != nil {
return nil,
}
, := bigmod.NewNat().SetBytes(, )
if != nil {
return nil,
}
, := bigmod.NewNat().SetBytes(, )
if != nil {
return nil,
}
:= &PrivateKey{
pub: PublicKey{
N: , E: ,
},
d: , p: , q: ,
dP: , dQ: , qInv: ,
}
if := checkPrivateKey(); != nil {
return nil,
}
return , nil
}
func ( []byte, int, []byte) (*PrivateKey, error) {
, := bigmod.NewModulus()
if != nil {
return nil,
}
, := bigmod.NewNat().SetBytes(, )
if != nil {
return nil,
}
:= &PrivateKey{
pub: PublicKey{
N: , E: ,
},
d: ,
}
if := checkPrivateKey(); != nil {
return nil,
}
return , nil
}
func ( *PrivateKey) () ( []byte, int, , , , , , []byte) {
= .pub.N.Nat().Bytes(.pub.N)
= .pub.E
= .d.Bytes(.pub.N)
if .dP == nil {
return
}
= .p.Nat().Bytes(.p)
= .q.Nat().Bytes(.q)
= bytes.Clone(.dP)
= bytes.Clone(.dQ)
= .qInv.Bytes(.p)
return
}
func ( *PrivateKey) error {
.fipsApproved = true
if , := checkPublicKey(&.pub); != nil {
return
} else if ! {
.fipsApproved = false
}
if .dP == nil {
.fipsApproved = false
return nil
}
:= .pub.N
:= .p
:= .q
if .BitLen() != .BitLen() {
.fipsApproved = false
}
:= bigmod.NewNat().ExpandFor()
if , := .SetBytes(.Nat().Bytes(), ); != nil {
return errors.New("crypto/rsa: invalid prime")
}
:= bigmod.NewNat().ExpandFor()
if , := .SetBytes(.Nat().Bytes(), ); != nil {
return errors.New("crypto/rsa: invalid prime")
}
if .Mul(, ).IsZero() != 1 {
return errors.New("crypto/rsa: p * q != n")
}
, := bigmod.NewModulus(.Nat().SubOne().Bytes())
if != nil {
return errors.New("crypto/rsa: invalid prime")
}
, := bigmod.NewNat().SetBytes(.dP, )
if != nil {
return errors.New("crypto/rsa: invalid CRT exponent")
}
:= bigmod.NewNat()
.SetUint(uint(.pub.E)).ExpandFor()
.Mul(, )
if .IsOne() != 1 {
return errors.New("crypto/rsa: invalid CRT exponent")
}
, := bigmod.NewModulus(.Nat().SubOne().Bytes())
if != nil {
return errors.New("crypto/rsa: invalid prime")
}
, := bigmod.NewNat().SetBytes(.dQ, )
if != nil {
return errors.New("crypto/rsa: invalid CRT exponent")
}
.SetUint(uint(.pub.E)).ExpandFor()
.Mul(, )
if .IsOne() != 1 {
return errors.New("crypto/rsa: invalid CRT exponent")
}
, := bigmod.NewNat().SetOverflowingBytes(.Nat().Bytes(), )
if != nil {
= bigmod.NewNat().Mod(.Nat(), )
}
if .Mul(.qInv, ).IsOne() != 1 {
return errors.New("crypto/rsa: invalid CRT coefficient")
}
:= bigmod.NewNat()
if , := bigmod.NewNat().SetBytes(.Nat().Bytes(), ); != nil {
, := bigmod.NewNat().SetBytes(.Nat().Bytes(), )
if != nil {
return errors.New("crypto/rsa: p == q")
}
.ExpandFor().Sub(, )
} else {
.ExpandFor().Sub(, )
}
if .BitLenVarTime() <= .BitLen()/2-100 {
return errors.New("crypto/rsa: |p - q| too small")
}
if .d.BitLenVarTime() <= .BitLen()/2 {
return errors.New("crypto/rsa: d too small")
}
return nil
}
func ( *PublicKey) ( bool, error) {
= true
if .N == nil {
return false, errors.New("crypto/rsa: missing public modulus")
}
if .N.Nat().IsOdd() == 0 {
return false, errors.New("crypto/rsa: public modulus is even")
}
if .N.BitLen() < 2048 {
= false
}
if .N.BitLen()%2 == 1 {
= false
}
if .E < 2 {
return false, errors.New("crypto/rsa: public exponent too small or negative")
}
if .E&1 == 0 {
return false, errors.New("crypto/rsa: public exponent is even")
}
if .E <= 1<<16 {
= false
}
if .E > 1<<31-1 {
return false, errors.New("crypto/rsa: public exponent too large")
}
return , nil
}
func ( *PublicKey, []byte) ([]byte, error) {
fips140.RecordNonApproved()
if , := checkPublicKey(); != nil {
return nil,
}
return encrypt(, )
}
func ( *PublicKey, []byte) ([]byte, error) {
, := bigmod.NewNat().SetBytes(, .N)
if != nil {
return nil,
}
return bigmod.NewNat().ExpShortVarTime(, uint(.E), .N).Bytes(.N), nil
}
var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA key size")
var ErrDecryption = errors.New("crypto/rsa: decryption error")
var ErrVerification = errors.New("crypto/rsa: verification error")
const withCheck = true
const noCheck = false
func ( *PrivateKey, []byte) ([]byte, error) {
fips140.RecordNonApproved()
return decrypt(, , noCheck)
}
func ( *PrivateKey, []byte) ([]byte, error) {
fips140.RecordNonApproved()
return decrypt(, , withCheck)
}
func ( *PrivateKey, []byte, bool) ([]byte, error) {
if !.fipsApproved {
fips140.RecordNonApproved()
}
var *bigmod.Nat
, := .pub.N, .pub.E
, := bigmod.NewNat().SetBytes(, )
if != nil {
return nil, ErrDecryption
}
if .dP == nil {
fips140.RecordNonApproved()
= bigmod.NewNat().Exp(, .d.Bytes(), )
} else {
, := .p, .q
:= bigmod.NewNat()
= bigmod.NewNat().Exp(.Mod(, ), .dP, )
:= bigmod.NewNat().Exp(.Mod(, ), .dQ, )
.Sub(.Mod(, ), )
.Mul(.qInv, )
.ExpandFor().Mul(.Mod(.Nat(), ), )
.Add(.ExpandFor(), )
}
if {
:= bigmod.NewNat().ExpShortVarTime(, uint(), )
if .Equal() != 1 {
return nil, ErrDecryption
}
}
return .Bytes(), nil
}