linux/lib/mpi
Ignat Korchagin f145d411a6 crypto: rsa - implement Chinese Remainder Theorem for faster private key operations
Changes from v1:
  * exported mpi_sub and mpi_mul, otherwise the build fails when RSA is a module

The kernel RSA ASN.1 private key parser already supports only private keys with
additional values to be used with the Chinese Remainder Theorem [1], but these
values are currently not used.

This rudimentary CRT implementation speeds up RSA private key operations for the
following Go benchmark up to ~3x.

This implementation also tries to minimise the allocation of additional MPIs,
so existing MPIs are reused as much as possible (hence the variable names are a
bit weird).

The benchmark used:

```
package keyring_test

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"io"
	"syscall"
	"testing"
	"unsafe"
)

type KeySerial int32
type Keyring int32

const (
	KEY_SPEC_PROCESS_KEYRING Keyring = -2
	KEYCTL_PKEY_SIGN                 = 27
)

var (
	keyTypeAsym = []byte("asymmetric\x00")
	sha256pkcs1 = []byte("enc=pkcs1 hash=sha256\x00")
)

func (keyring Keyring) LoadAsym(desc string, payload []byte) (KeySerial, error) {
	cdesc := []byte(desc + "\x00")
	serial, _, errno := syscall.Syscall6(syscall.SYS_ADD_KEY, uintptr(unsafe.Pointer(&keyTypeAsym[0])), uintptr(unsafe.Pointer(&cdesc[0])), uintptr(unsafe.Pointer(&payload[0])), uintptr(len(payload)), uintptr(keyring), uintptr(0))
	if errno == 0 {
		return KeySerial(serial), nil
	}

	return KeySerial(serial), errno
}

type pkeyParams struct {
	key_id         KeySerial
	in_len         uint32
	out_or_in2_len uint32
	__spare        [7]uint32
}

// the output signature buffer is an input parameter here, because we want to
// avoid Go buffer allocation leaking into our benchmarks
func (key KeySerial) Sign(info, digest, out []byte) error {
	var params pkeyParams
	params.key_id = key
	params.in_len = uint32(len(digest))
	params.out_or_in2_len = uint32(len(out))

	_, _, errno := syscall.Syscall6(syscall.SYS_KEYCTL, KEYCTL_PKEY_SIGN, uintptr(unsafe.Pointer(&params)), uintptr(unsafe.Pointer(&info[0])), uintptr(unsafe.Pointer(&digest[0])), uintptr(unsafe.Pointer(&out[0])), uintptr(0))
	if errno == 0 {
		return nil
	}

	return errno
}

func BenchmarkSign(b *testing.B) {
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		b.Fatalf("failed to generate private key: %v", err)
	}

	pkcs8, err := x509.MarshalPKCS8PrivateKey(priv)
	if err != nil {
		b.Fatalf("failed to serialize the private key to PKCS8 blob: %v", err)
	}

	serial, err := KEY_SPEC_PROCESS_KEYRING.LoadAsym("test rsa key", pkcs8)
	if err != nil {
		b.Fatalf("failed to load the private key into the keyring: %v", err)
	}

	b.Logf("loaded test rsa key: %v", serial)

	digest := make([]byte, 32)
	_, err = io.ReadFull(rand.Reader, digest)
	if err != nil {
		b.Fatalf("failed to generate a random digest: %v", err)
	}

	sig := make([]byte, 256)
	for n := 0; n < b.N; n++ {
		err = serial.Sign(sha256pkcs1, digest, sig)
		if err != nil {
			b.Fatalf("failed to sign the digest: %v", err)
		}
	}

	err = rsa.VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, digest, sig)
	if err != nil {
		b.Fatalf("failed to verify the signature: %v", err)
	}
}
```

[1]: https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Using_the_Chinese_remainder_algorithm

Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2022-06-24 17:12:29 +08:00
..
ec.c lib/mpi: Remove unused scalar_copied 2020-10-30 17:34:45 +11:00
generic_mpih-add1.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
generic_mpih-lshift.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
generic_mpih-mul1.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
generic_mpih-mul2.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
generic_mpih-mul3.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
generic_mpih-rshift.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
generic_mpih-sub1.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
longlong.h lib/mpi: fix spelling mistakes 2021-07-01 11:06:05 -07:00
Makefile lib/mpi: Introduce ec implementation to MPI library 2020-09-25 17:48:54 +10:00
mpi-add.c crypto: rsa - implement Chinese Remainder Theorem for faster private key operations 2022-06-24 17:12:29 +08:00
mpi-bit.c lib/mpi: export mpi_rshift 2022-03-03 10:47:52 +12:00
mpi-cmp.c lib/mpi: Extend the MPI library 2020-09-25 17:48:53 +10:00
mpi-div.c lib/mpi: Fix unused variable warnings 2020-10-02 18:02:13 +10:00
mpi-inline.h treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
mpi-internal.h lib/mpi: Fix unused variable warnings 2020-10-02 18:02:13 +10:00
mpi-inv.c lib/mpi: Extend the MPI library 2020-09-25 17:48:53 +10:00
mpi-mod.c lib/mpi: Add the return value check of kcalloc() 2022-01-07 14:30:01 +11:00
mpi-mul.c crypto: rsa - implement Chinese Remainder Theorem for faster private key operations 2022-06-24 17:12:29 +08:00
mpi-pow.c Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6 2019-07-05 13:31:19 +09:00
mpi-sub-ui.c lib/mpi: Add mpi_sub_ui() 2020-07-31 18:08:59 +10:00
mpicoder.c lib/mpi: fix spelling mistakes 2021-07-01 11:06:05 -07:00
mpih-cmp.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 26 2019-05-24 17:27:10 +02:00
mpih-div.c lib/mpi: Fix unused variable warnings 2020-10-02 18:02:13 +10:00
mpih-mul.c lib/mpi: Extend the MPI library 2020-09-25 17:48:53 +10:00
mpiutil.c lib/mpi: use kcalloc in mpi_resize 2021-08-12 19:17:00 +08:00