package crypto

import (
	
	
	
	
	
	
	

	pb 
	
)

// RsaPrivateKey is a rsa private key
type RsaPrivateKey struct {
	sk rsa.PrivateKey
}

// RsaPublicKey is a rsa public key
type RsaPublicKey struct {
	k rsa.PublicKey

	cached []byte
}

// GenerateRSAKeyPair generates a new rsa private and public key
func ( int,  io.Reader) (PrivKey, PubKey, error) {
	if  < MinRsaKeyBits {
		return nil, nil, ErrRsaKeyTooSmall
	}
	if  > maxRsaKeyBits {
		return nil, nil, ErrRsaKeyTooBig
	}
	,  := rsa.GenerateKey(, )
	if  != nil {
		return nil, nil, 
	}
	 := .PublicKey
	return &RsaPrivateKey{sk: *}, &RsaPublicKey{k: }, nil
}

// Verify compares a signature against input data
func ( *RsaPublicKey) (,  []byte) ( bool,  error) {
	defer func() {
		catch.HandlePanic(recover(), &, "RSA signature verification")

		// To be safe
		if  != nil {
			 = false
		}
	}()
	 := sha256.Sum256()
	 = rsa.VerifyPKCS1v15(&.k, crypto.SHA256, [:], )
	if  != nil {
		return false, 
	}
	return true, nil
}

func ( *RsaPublicKey) () pb.KeyType {
	return pb.KeyType_RSA
}

func ( *RsaPublicKey) () ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "RSA public-key marshaling") }()
	return x509.MarshalPKIXPublicKey(&.k)
}

// Equals checks whether this key is equal to another
func ( *RsaPublicKey) ( Key) bool {
	// make sure this is a rsa public key
	,  := ().(*RsaPublicKey)
	if ! {
		return basicEquals(, )
	}

	return .k.N.Cmp(.k.N) == 0 && .k.E == .k.E
}

// Sign returns a signature of the input data
func ( *RsaPrivateKey) ( []byte) ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "RSA signing") }()
	 := sha256.Sum256()
	return rsa.SignPKCS1v15(rand.Reader, &.sk, crypto.SHA256, [:])
}

// GetPublic returns a public key
func ( *RsaPrivateKey) () PubKey {
	return &RsaPublicKey{k: .sk.PublicKey}
}

func ( *RsaPrivateKey) () pb.KeyType {
	return pb.KeyType_RSA
}

func ( *RsaPrivateKey) () ( []byte,  error) {
	defer func() { catch.HandlePanic(recover(), &, "RSA private-key marshaling") }()
	 := x509.MarshalPKCS1PrivateKey(&.sk)
	return , nil
}

// Equals checks whether this key is equal to another
func ( *RsaPrivateKey) ( Key) bool {
	// make sure this is a rsa public key
	,  := ().(*RsaPrivateKey)
	if ! {
		return basicEquals(, )
	}

	 := .sk
	 := .sk

	// Don't care about constant time. We're only comparing the public half.
	return .PublicKey.N.Cmp(.PublicKey.N) == 0 && .PublicKey.E == .PublicKey.E
}

// UnmarshalRsaPrivateKey returns a private key from the input x509 bytes
func ( []byte) ( PrivKey,  error) {
	defer func() { catch.HandlePanic(recover(), &, "RSA private-key unmarshaling") }()
	,  := x509.ParsePKCS1PrivateKey()
	if  != nil {
		return nil, 
	}
	if .N.BitLen() < MinRsaKeyBits {
		return nil, ErrRsaKeyTooSmall
	}
	if .N.BitLen() > maxRsaKeyBits {
		return nil, ErrRsaKeyTooBig
	}
	return &RsaPrivateKey{sk: *}, nil
}

// UnmarshalRsaPublicKey returns a public key from the input x509 bytes
func ( []byte) ( PubKey,  error) {
	defer func() { catch.HandlePanic(recover(), &, "RSA public-key unmarshaling") }()
	,  := x509.ParsePKIXPublicKey()
	if  != nil {
		return nil, 
	}
	,  := .(*rsa.PublicKey)
	if ! {
		return nil, errors.New("not actually an rsa public key")
	}
	if .N.BitLen() < MinRsaKeyBits {
		return nil, ErrRsaKeyTooSmall
	}
	if .N.BitLen() > maxRsaKeyBits {
		return nil, ErrRsaKeyTooBig
	}

	return &RsaPublicKey{k: *}, nil
}