2022-05-14 04:25:26

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v6 0/9] Introduce akcipher service for virtio-crypto

v5 -> v6:
- Fix build errors and codestyles.
- Add parameter 'Error **errp' for qcrypto_akcipher_rsakey_parse.
- Report more detailed errors.
- Fix buffer length check and return values of akcipher-nettle, allows caller to
pass a buffer with larger size than actual needed.

A million thanks to Daniel!

v4 -> v5:
- Move QCryptoAkCipher into akcipherpriv.h, and modify the related comments.
- Rename asn1_decoder.c to der.c.
- Code style fix: use 'cleanup' & 'error' lables.
- Allow autoptr type to auto-free.
- Add test cases for rsakey to handle DER error.
- Other minor fixes.

v3 -> v4:
- Coding style fix: Akcipher -> AkCipher, struct XXX -> XXX, Rsa -> RSA,
XXX-alg -> XXX-algo.
- Change version info in qapi/crypto.json, from 7.0 -> 7.1.
- Remove ecdsa from qapi/crypto.json, it would be introduced with the implemetion later.
- Use QCryptoHashAlgothrim instead of QCryptoRSAHashAlgorithm(removed) in qapi/crypto.json.
- Rename arguments of qcrypto_akcipher_XXX to keep aligned with qcrypto_cipher_XXX(dec/enc/sign/vefiry -> in/out/in2), and add qcrypto_akcipher_max_XXX APIs.
- Add new API: qcrypto_akcipher_supports.
- Change the return value of qcrypto_akcipher_enc/dec/sign, these functions return the actual length of result.
- Separate ASN.1 source code and test case clean.
- Disable RSA raw encoding for akcipher-nettle.
- Separate RSA key parser into rsakey.{hc}, and implememts it with builtin-asn1-decoder and nettle respectivly.
- Implement RSA(pkcs1 and raw encoding) algorithm by gcrypt. This has higher priority than nettle.
- For some akcipher operations(eg, decryption of pkcs1pad(rsa)), the length of returned result maybe less than the dst buffer size, return the actual length of result instead of the buffer length to the guest side. (in function virtio_crypto_akcipher_input_data_helper)
- Other minor changes.

Thanks to Daniel!

Eric pointed out this missing part of use case, send it here again.

In our plan, the feature is designed for HTTPS offloading case and other applications which use kernel RSA/ecdsa by keyctl syscall. The full picture shows bellow:


Nginx/openssl[1] ... Apps
Guest -----------------------------------------
virtio-crypto driver[2]
-------------------------------------------------
virtio-crypto backend[3]
Host -----------------------------------------
/ | \
builtin[4] vhost keyctl[5] ...


[1] User applications can offload RSA calculation to kernel by keyctl syscall. There is no keyctl engine in openssl currently, we developed a engine and tried to contribute it to openssl upstream, but openssl 1.x does not accept new feature. Link:
https://github.com/openssl/openssl/pull/16689

This branch is available and maintained by Lei <[email protected]>
https://github.com/TousakaRin/openssl/tree/OpenSSL_1_1_1-kctl_engine

We tested nginx(change config file only) with openssl keyctl engine, it works fine.

[2] virtio-crypto driver is used to communicate with host side, send requests to host side to do asymmetric calculation.
https://lkml.org/lkml/2022/3/1/1425

[3] virtio-crypto backend handles requests from guest side, and forwards request to crypto backend driver of QEMU.

[4] Currently RSA is supported only in builtin driver. This driver is supposed to test the full feature without other software(Ex vhost process) and hardware dependence. ecdsa is introduced into qapi type without implementation, this may be implemented in Q3-2022 or later. If ecdsa type definition should be added with the implementation together, I'll remove this in next version.

[5] keyctl backend is in development, we will post this feature in Q2-2022. keyctl backend can use hardware acceleration(Ex, Intel QAT).

Setup the full environment, tested with Intel QAT on host side, the QPS of HTTPS increase to ~200% in a guest.

VS PCI passthrough: the most important benefit of this solution makes the VM migratable.

v2 -> v3:
- Introduce akcipher types to qapi
- Add test/benchmark suite for akcipher class
- Seperate 'virtio_crypto: Support virtio crypto asym operation' into:
- crypto: Introduce akcipher crypto class
- virtio-crypto: Introduce RSA algorithm

v1 -> v2:
- Update virtio_crypto.h from v2 version of related kernel patch.

v1:
- Support akcipher for virtio-crypto.
- Introduce akcipher class.
- Introduce ASN1 decoder into QEMU.
- Implement RSA backend by nettle/hogweed.

Lei He (6):
qapi: crypto-akcipher: Introduce akcipher types to qapi
crypto: add ASN.1 DER decoder
crypto: Implement RSA algorithm by hogweed
crypto: Implement RSA algorithm by gcrypt
test/crypto: Add test suite for crypto akcipher
tests/crypto: Add test suite for RSA keys

Zhenwei Pi (3):
virtio-crypto: header update
crypto: Introduce akcipher crypto class
crypto: Introduce RSA algorithm

backends/cryptodev-builtin.c | 272 ++++-
backends/cryptodev-vhost-user.c | 34 +-
backends/cryptodev.c | 32 +-
crypto/akcipher-gcrypt.c.inc | 597 +++++++++++
crypto/akcipher-nettle.c.inc | 451 ++++++++
crypto/akcipher.c | 108 ++
crypto/akcipherpriv.h | 55 +
crypto/der.c | 189 ++++
crypto/der.h | 81 ++
crypto/meson.build | 6 +
crypto/rsakey-builtin.c.inc | 200 ++++
crypto/rsakey-nettle.c.inc | 158 +++
crypto/rsakey.c | 44 +
crypto/rsakey.h | 94 ++
hw/virtio/virtio-crypto.c | 323 ++++--
include/crypto/akcipher.h | 158 +++
include/hw/virtio/virtio-crypto.h | 5 +-
.../standard-headers/linux/virtio_crypto.h | 82 +-
include/sysemu/cryptodev.h | 83 +-
meson.build | 11 +
qapi/crypto.json | 64 ++
tests/bench/benchmark-crypto-akcipher.c | 157 +++
tests/bench/meson.build | 1 +
tests/bench/test_akcipher_keys.inc | 537 ++++++++++
tests/unit/meson.build | 2 +
tests/unit/test-crypto-akcipher.c | 990 ++++++++++++++++++
tests/unit/test-crypto-der.c | 290 +++++
27 files changed, 4878 insertions(+), 146 deletions(-)
create mode 100644 crypto/akcipher-gcrypt.c.inc
create mode 100644 crypto/akcipher-nettle.c.inc
create mode 100644 crypto/akcipher.c
create mode 100644 crypto/akcipherpriv.h
create mode 100644 crypto/der.c
create mode 100644 crypto/der.h
create mode 100644 crypto/rsakey-builtin.c.inc
create mode 100644 crypto/rsakey-nettle.c.inc
create mode 100644 crypto/rsakey.c
create mode 100644 crypto/rsakey.h
create mode 100644 include/crypto/akcipher.h
create mode 100644 tests/bench/benchmark-crypto-akcipher.c
create mode 100644 tests/bench/test_akcipher_keys.inc
create mode 100644 tests/unit/test-crypto-akcipher.c
create mode 100644 tests/unit/test-crypto-der.c

--
2.20.1



2022-05-14 04:25:25

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v6 7/9] test/crypto: Add test suite for crypto akcipher

From: Lei He <[email protected]>

Add unit test and benchmark test for crypto akcipher.

Signed-off-by: lei he <[email protected]>
Signed-off-by: zhenwei pi <[email protected]>
Reviewed-by: Daniel P. Berrangé <[email protected]>
---
tests/bench/benchmark-crypto-akcipher.c | 157 ++++++
tests/bench/meson.build | 1 +
tests/bench/test_akcipher_keys.inc | 537 ++++++++++++++++++
tests/unit/meson.build | 1 +
tests/unit/test-crypto-akcipher.c | 711 ++++++++++++++++++++++++
5 files changed, 1407 insertions(+)
create mode 100644 tests/bench/benchmark-crypto-akcipher.c
create mode 100644 tests/bench/test_akcipher_keys.inc
create mode 100644 tests/unit/test-crypto-akcipher.c

diff --git a/tests/bench/benchmark-crypto-akcipher.c b/tests/bench/benchmark-crypto-akcipher.c
new file mode 100644
index 0000000000..c6c80c0be1
--- /dev/null
+++ b/tests/bench/benchmark-crypto-akcipher.c
@@ -0,0 +1,157 @@
+/*
+ * QEMU Crypto akcipher speed benchmark
+ *
+ * Copyright (c) 2022 Bytedance
+ *
+ * Authors:
+ * lei he <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/init.h"
+#include "crypto/akcipher.h"
+#include "standard-headers/linux/virtio_crypto.h"
+
+#include "test_akcipher_keys.inc"
+
+static bool keep_running;
+
+static void alarm_handler(int sig)
+{
+ keep_running = false;
+}
+
+static QCryptoAkCipher *create_rsa_akcipher(const uint8_t *priv_key,
+ size_t keylen,
+ QCryptoRSAPaddingAlgorithm padding,
+ QCryptoHashAlgorithm hash)
+{
+ QCryptoAkCipherOptions opt;
+ QCryptoAkCipher *rsa;
+
+ opt.alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ opt.u.rsa.padding_alg = padding;
+ opt.u.rsa.hash_alg = hash;
+ rsa = qcrypto_akcipher_new(&opt, QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ priv_key, keylen, &error_abort);
+ return rsa;
+}
+
+static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
+ size_t key_size)
+{
+#define BYTE 8
+#define SHA1_DGST_LEN 20
+#define DURATION_SECONDS 10
+#define PADDING QCRYPTO_RSA_PADDING_ALG_PKCS1
+#define HASH QCRYPTO_HASH_ALG_SHA1
+
+ g_autoptr(QCryptoAkCipher) rsa =
+ create_rsa_akcipher(priv_key, keylen, PADDING, HASH);
+ g_autofree uint8_t *dgst = NULL;
+ g_autofree uint8_t *signature = NULL;
+ size_t count;
+
+ dgst = g_new0(uint8_t, SHA1_DGST_LEN);
+ memset(dgst, g_test_rand_int(), SHA1_DGST_LEN);
+ signature = g_new0(uint8_t, key_size / BYTE);
+
+ g_test_message("benchmark rsa%lu (%s-%s) sign in %d seconds", key_size,
+ QCryptoRSAPaddingAlgorithm_str(PADDING),
+ QCryptoHashAlgorithm_str(HASH),
+ DURATION_SECONDS);
+ alarm(DURATION_SECONDS);
+ g_test_timer_start();
+ for (keep_running = true, count = 0; keep_running; ++count) {
+ g_assert(qcrypto_akcipher_sign(rsa, dgst, SHA1_DGST_LEN,
+ signature, key_size / BYTE,
+ &error_abort) > 0);
+ }
+ g_test_timer_elapsed();
+ g_test_message("rsa%lu (%s-%s) sign %lu times in %.2f seconds,"
+ " %.2f times/sec ",
+ key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
+ QCryptoHashAlgorithm_str(HASH),
+ count, g_test_timer_last(),
+ (double)count / g_test_timer_last());
+
+ g_test_message("benchmark rsa%lu (%s-%s) verify in %d seconds", key_size,
+ QCryptoRSAPaddingAlgorithm_str(PADDING),
+ QCryptoHashAlgorithm_str(HASH),
+ DURATION_SECONDS);
+ alarm(DURATION_SECONDS);
+ g_test_timer_start();
+ for (keep_running = true, count = 0; keep_running; ++count) {
+ g_assert(qcrypto_akcipher_verify(rsa, signature, key_size / BYTE,
+ dgst, SHA1_DGST_LEN,
+ &error_abort) == 0);
+ }
+ g_test_timer_elapsed();
+ g_test_message("rsa%lu (%s-%s) verify %lu times in %.2f seconds,"
+ " %.2f times/sec ",
+ key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
+ QCryptoHashAlgorithm_str(HASH),
+ count, g_test_timer_last(),
+ (double)count / g_test_timer_last());
+}
+
+static void test_rsa_1024_speed(const void *opaque)
+{
+ size_t key_size = (size_t)opaque;
+ test_rsa_speed(rsa1024_priv_key, sizeof(rsa1024_priv_key), key_size);
+}
+
+static void test_rsa_2048_speed(const void *opaque)
+{
+ size_t key_size = (size_t)opaque;
+ test_rsa_speed(rsa2048_priv_key, sizeof(rsa2048_priv_key), key_size);
+}
+
+static void test_rsa_4096_speed(const void *opaque)
+{
+ size_t key_size = (size_t)opaque;
+ test_rsa_speed(rsa4096_priv_key, sizeof(rsa4096_priv_key), key_size);
+}
+
+int main(int argc, char **argv)
+{
+ char *alg = NULL;
+ char *size = NULL;
+ g_test_init(&argc, &argv, NULL);
+ g_assert(qcrypto_init(NULL) == 0);
+ struct sigaction new_action, old_action;
+
+ new_action.sa_handler = alarm_handler;
+
+ /* Set up the structure to specify the new action. */
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = 0;
+ sigaction(SIGALRM, NULL, &old_action);
+ g_assert(old_action.sa_handler != SIG_IGN);
+ sigaction(SIGALRM, &new_action, NULL);
+
+#define ADD_TEST(asym_alg, keysize) \
+ if ((!alg || g_str_equal(alg, #asym_alg)) && \
+ (!size || g_str_equal(size, #keysize))) \
+ g_test_add_data_func( \
+ "/crypto/akcipher/" #asym_alg "-" #keysize, \
+ (void *)keysize, \
+ test_ ## asym_alg ## _ ## keysize ## _speed)
+
+ if (argc >= 2) {
+ alg = argv[1];
+ }
+ if (argc >= 3) {
+ size = argv[2];
+ }
+
+ ADD_TEST(rsa, 1024);
+ ADD_TEST(rsa, 2048);
+ ADD_TEST(rsa, 4096);
+
+ return g_test_run();
+}
diff --git a/tests/bench/meson.build b/tests/bench/meson.build
index 00b3c209dc..279a8fcc33 100644
--- a/tests/bench/meson.build
+++ b/tests/bench/meson.build
@@ -20,6 +20,7 @@ if have_block
'benchmark-crypto-hash': [crypto],
'benchmark-crypto-hmac': [crypto],
'benchmark-crypto-cipher': [crypto],
+ 'benchmark-crypto-akcipher': [crypto],
}
endif

diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc
new file mode 100644
index 0000000000..df3eccb45e
--- /dev/null
+++ b/tests/bench/test_akcipher_keys.inc
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2022 Bytedance, and/or its affiliates
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Author: lei he <[email protected]>
+ */
+
+/* RSA test keys, generated by OpenSSL */
+static const uint8_t rsa1024_priv_key[] = {
+ 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02,
+ 0x81, 0x81, 0x00, 0xe6, 0x4d, 0x76, 0x4f, 0xb2,
+ 0x97, 0x09, 0xad, 0x9d, 0x17, 0x33, 0xf2, 0x30,
+ 0x42, 0x83, 0xa9, 0xcb, 0x49, 0xa4, 0x2e, 0x59,
+ 0x5e, 0x75, 0x51, 0xd1, 0xac, 0xc8, 0x86, 0x3e,
+ 0xdb, 0x72, 0x2e, 0xb2, 0xf7, 0xc3, 0x5b, 0xc7,
+ 0xea, 0xed, 0x30, 0xd1, 0xf7, 0x37, 0xee, 0x9d,
+ 0x36, 0x59, 0x6f, 0xf8, 0xce, 0xc0, 0x5c, 0x82,
+ 0x80, 0x37, 0x83, 0xd7, 0x45, 0x6a, 0xe9, 0xea,
+ 0xc5, 0x3a, 0x59, 0x6b, 0x34, 0x31, 0x44, 0x00,
+ 0x74, 0xa7, 0x29, 0xab, 0x79, 0x4a, 0xbd, 0xe8,
+ 0x25, 0x35, 0x01, 0x11, 0x40, 0xbf, 0x31, 0xbd,
+ 0xd3, 0xe0, 0x68, 0x1e, 0xd5, 0x5b, 0x2f, 0xe9,
+ 0x20, 0xf2, 0x9f, 0x46, 0x35, 0x30, 0xa8, 0xf1,
+ 0xfe, 0xef, 0xd8, 0x76, 0x23, 0x46, 0x34, 0x70,
+ 0xa1, 0xce, 0xc6, 0x65, 0x6d, 0xb0, 0x94, 0x7e,
+ 0xe5, 0x92, 0x45, 0x7b, 0xaa, 0xbb, 0x95, 0x97,
+ 0x77, 0xcd, 0xd3, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x02, 0x81, 0x80, 0x30, 0x6a, 0xc4, 0x9e, 0xc8,
+ 0xba, 0xfc, 0x2b, 0xe5, 0xc4, 0xc5, 0x04, 0xfb,
+ 0xa4, 0x60, 0x2d, 0xc8, 0x31, 0x39, 0x35, 0x0d,
+ 0x50, 0xd0, 0x75, 0x5d, 0x11, 0x68, 0x2e, 0xe0,
+ 0xf4, 0x1d, 0xb3, 0x37, 0xa8, 0xe3, 0x07, 0x5e,
+ 0xa6, 0x43, 0x2b, 0x6a, 0x59, 0x01, 0x07, 0x47,
+ 0x41, 0xef, 0xd7, 0x9c, 0x85, 0x4a, 0xe7, 0xa7,
+ 0xff, 0xf0, 0xab, 0xe5, 0x0c, 0x11, 0x08, 0x10,
+ 0x75, 0x5a, 0x68, 0xa0, 0x08, 0x03, 0xc9, 0x40,
+ 0x79, 0x67, 0x1d, 0x65, 0x89, 0x2d, 0x08, 0xf9,
+ 0xb5, 0x1b, 0x7d, 0xd2, 0x41, 0x3b, 0x33, 0xf2,
+ 0x47, 0x2f, 0x9c, 0x0b, 0xd5, 0xaf, 0xcb, 0xdb,
+ 0xbb, 0x37, 0x63, 0x03, 0xf8, 0xe7, 0x2e, 0xc7,
+ 0x3c, 0x86, 0x9f, 0xc2, 0x9b, 0xb4, 0x70, 0x6a,
+ 0x4d, 0x7c, 0xe4, 0x1b, 0x3a, 0xa9, 0xae, 0xd7,
+ 0xce, 0x7f, 0x56, 0xc2, 0x73, 0x5e, 0x58, 0x63,
+ 0xd5, 0x86, 0x41, 0x02, 0x41, 0x00, 0xf6, 0x56,
+ 0x69, 0xec, 0xef, 0x65, 0x95, 0xdc, 0x25, 0x47,
+ 0xe0, 0x6f, 0xb0, 0x4f, 0x79, 0x77, 0x0a, 0x5e,
+ 0x46, 0xcb, 0xbd, 0x0b, 0x71, 0x51, 0x2a, 0xa4,
+ 0x65, 0x29, 0x18, 0xc6, 0x30, 0xa0, 0x95, 0x4c,
+ 0x4b, 0xbe, 0x8c, 0x40, 0xe3, 0x9c, 0x23, 0x02,
+ 0x14, 0x43, 0xe9, 0x64, 0xea, 0xe3, 0xa8, 0xe2,
+ 0x1a, 0xd5, 0xf9, 0x5c, 0xe0, 0x36, 0x2c, 0x97,
+ 0xda, 0xd5, 0xc7, 0x46, 0xce, 0x11, 0x02, 0x41,
+ 0x00, 0xef, 0x56, 0x08, 0xb8, 0x29, 0xa5, 0xa6,
+ 0x7c, 0xf7, 0x5f, 0xb4, 0xf5, 0x63, 0xe7, 0xeb,
+ 0x45, 0xfd, 0x89, 0xaa, 0x94, 0xa6, 0x3d, 0x0b,
+ 0xd9, 0x04, 0x6f, 0x78, 0xe0, 0xbb, 0xa2, 0xd4,
+ 0x29, 0x83, 0x17, 0x95, 0x6f, 0x50, 0x3d, 0x40,
+ 0x5d, 0xe5, 0x24, 0xda, 0xc2, 0x23, 0x50, 0x86,
+ 0xa8, 0x34, 0xc8, 0x6f, 0xec, 0x7f, 0xb6, 0x45,
+ 0x3a, 0xdd, 0x78, 0x9b, 0xee, 0xa1, 0xe4, 0x09,
+ 0xa3, 0x02, 0x40, 0x5c, 0xd6, 0x66, 0x67, 0x58,
+ 0x35, 0xc5, 0xcb, 0xc8, 0xf5, 0x14, 0xbd, 0xa3,
+ 0x09, 0xe0, 0xb2, 0x1f, 0x63, 0x36, 0x75, 0x34,
+ 0x52, 0xea, 0xaa, 0xf7, 0x52, 0x2b, 0x99, 0xd8,
+ 0x6f, 0x61, 0x06, 0x34, 0x1e, 0x23, 0xf1, 0xb5,
+ 0x34, 0x03, 0x53, 0xe5, 0xd1, 0xb3, 0xc7, 0x80,
+ 0x5f, 0x7b, 0x32, 0xbf, 0x84, 0x2f, 0x2e, 0xf3,
+ 0x22, 0xb0, 0x91, 0x5a, 0x2f, 0x04, 0xd7, 0x4a,
+ 0x9a, 0x01, 0xb1, 0x02, 0x40, 0x34, 0x0b, 0x26,
+ 0x4c, 0x3d, 0xaa, 0x2a, 0xc0, 0xe3, 0xdd, 0xe8,
+ 0xf0, 0xaf, 0x6f, 0xe0, 0x06, 0x51, 0x32, 0x9d,
+ 0x68, 0x43, 0x99, 0xe4, 0xb8, 0xa5, 0x31, 0x44,
+ 0x3c, 0xc2, 0x30, 0x8f, 0x28, 0x13, 0xbc, 0x8e,
+ 0x1f, 0x2d, 0x78, 0x94, 0x45, 0x96, 0xad, 0x63,
+ 0xf0, 0x71, 0x53, 0x72, 0x64, 0xa3, 0x4d, 0xae,
+ 0xa0, 0xe3, 0xc8, 0x93, 0xd7, 0x50, 0x0f, 0x89,
+ 0x00, 0xe4, 0x2d, 0x3d, 0x37, 0x02, 0x41, 0x00,
+ 0xbe, 0xa6, 0x08, 0xe0, 0xc8, 0x15, 0x2a, 0x47,
+ 0xcb, 0xd5, 0xec, 0x93, 0xd3, 0xaa, 0x12, 0x82,
+ 0xaf, 0xac, 0x51, 0x5a, 0x5b, 0xa7, 0x93, 0x4b,
+ 0xb9, 0xab, 0x00, 0xfa, 0x5a, 0xea, 0x34, 0xe4,
+ 0x80, 0xf1, 0x44, 0x6a, 0x65, 0xe4, 0x33, 0x99,
+ 0xfb, 0x54, 0xd7, 0x89, 0x5a, 0x1b, 0xd6, 0x2b,
+ 0xcc, 0x6e, 0x4b, 0x19, 0xa0, 0x6d, 0x93, 0x9f,
+ 0xc3, 0x91, 0x7a, 0xa5, 0xd8, 0x59, 0x0e, 0x9e,
+};
+
+static const uint8_t rsa2048_priv_key[] = {
+ 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02,
+ 0x82, 0x01, 0x01, 0x00, 0xbd, 0x9c, 0x83, 0x6b,
+ 0x0e, 0x8e, 0xcf, 0xfa, 0xaa, 0x4f, 0x6a, 0xf4,
+ 0xe3, 0x52, 0x0f, 0xa5, 0xd0, 0xbe, 0x5e, 0x7f,
+ 0x08, 0x24, 0xba, 0x87, 0x46, 0xfb, 0x28, 0x93,
+ 0xe5, 0xe5, 0x81, 0x42, 0xc0, 0xf9, 0x17, 0xc7,
+ 0x81, 0x01, 0xf4, 0x18, 0x6a, 0x17, 0xf5, 0x57,
+ 0x20, 0x37, 0xcf, 0xf9, 0x74, 0x5e, 0xe1, 0x48,
+ 0x6a, 0x71, 0x0a, 0x0f, 0x79, 0x72, 0x2b, 0x46,
+ 0x10, 0x53, 0xdc, 0x14, 0x43, 0xbd, 0xbc, 0x6d,
+ 0x15, 0x6f, 0x15, 0x4e, 0xf0, 0x0d, 0x89, 0x39,
+ 0x02, 0xc3, 0x68, 0x5c, 0xa8, 0xfc, 0xed, 0x64,
+ 0x9d, 0x98, 0xb7, 0xcd, 0x83, 0x66, 0x93, 0xc3,
+ 0xd9, 0x57, 0xa0, 0x21, 0x93, 0xad, 0x5c, 0x75,
+ 0x69, 0x88, 0x9e, 0x81, 0xdc, 0x7f, 0x1d, 0xd5,
+ 0xbd, 0x1c, 0xc1, 0x30, 0x56, 0xa5, 0xda, 0x99,
+ 0x46, 0xa6, 0x6d, 0x0e, 0x6f, 0x5e, 0x51, 0x34,
+ 0x49, 0x73, 0xc3, 0x67, 0x49, 0x7e, 0x21, 0x2a,
+ 0x20, 0xa7, 0x2b, 0x92, 0x73, 0x1d, 0xa5, 0x25,
+ 0x2a, 0xd0, 0x3a, 0x89, 0x75, 0xb2, 0xbb, 0x19,
+ 0x37, 0x78, 0x48, 0xd2, 0xf2, 0x2a, 0x6d, 0x9e,
+ 0xc6, 0x26, 0xca, 0x46, 0x8c, 0xf1, 0x42, 0x2a,
+ 0x31, 0xb2, 0xfc, 0xe7, 0x55, 0x51, 0xff, 0x07,
+ 0x13, 0x5b, 0x36, 0x59, 0x2b, 0x43, 0x30, 0x4b,
+ 0x05, 0x5c, 0xd2, 0x45, 0xa0, 0xa0, 0x7c, 0x17,
+ 0x5b, 0x07, 0xbb, 0x5d, 0x83, 0x80, 0x92, 0x6d,
+ 0x87, 0x1a, 0x43, 0xac, 0xc7, 0x6b, 0x8d, 0x11,
+ 0x60, 0x27, 0xd2, 0xdf, 0xdb, 0x71, 0x02, 0x55,
+ 0x6e, 0xb5, 0xca, 0x4d, 0xda, 0x59, 0x0d, 0xb8,
+ 0x8c, 0xcd, 0xd3, 0x0e, 0x55, 0xa0, 0xa4, 0x8d,
+ 0xa0, 0x14, 0x10, 0x48, 0x42, 0x35, 0x56, 0x08,
+ 0xf7, 0x29, 0x5f, 0xa2, 0xea, 0xa4, 0x5e, 0x8e,
+ 0x99, 0x56, 0xaa, 0x5a, 0x8c, 0x23, 0x8f, 0x35,
+ 0x22, 0x8a, 0xff, 0xed, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0x02, 0x82, 0x01, 0x00, 0x4e, 0x4a, 0xf3,
+ 0x44, 0xe0, 0x64, 0xfd, 0xe1, 0xde, 0x33, 0x1e,
+ 0xd1, 0xf1, 0x8f, 0x6f, 0xe0, 0xa2, 0xfa, 0x08,
+ 0x60, 0xe1, 0xc6, 0xf0, 0xb2, 0x6d, 0x0f, 0xc6,
+ 0x28, 0x93, 0xb4, 0x19, 0x94, 0xab, 0xc3, 0xef,
+ 0x1a, 0xb4, 0xdd, 0x4e, 0xa2, 0x4a, 0x24, 0x8c,
+ 0x6c, 0xa6, 0x64, 0x05, 0x5f, 0x56, 0xba, 0xda,
+ 0xc1, 0x21, 0x1a, 0x7d, 0xf1, 0xf7, 0xce, 0xb9,
+ 0xa9, 0x9b, 0x92, 0x54, 0xfc, 0x95, 0x20, 0x22,
+ 0x4e, 0xd4, 0x9b, 0xe2, 0xab, 0x8e, 0x99, 0xb8,
+ 0x40, 0xaf, 0x30, 0x6a, 0xc6, 0x60, 0x0c, 0xd8,
+ 0x25, 0x44, 0xa1, 0xcb, 0xbb, 0x73, 0x77, 0x86,
+ 0xaa, 0x46, 0xf3, 0x54, 0xae, 0xa8, 0xa0, 0xdb,
+ 0xdd, 0xab, 0x6e, 0xfb, 0x2c, 0x5a, 0x14, 0xaf,
+ 0x08, 0x13, 0xa7, 0x6c, 0xe9, 0xfd, 0xcd, 0x4c,
+ 0x1f, 0x20, 0x3a, 0x16, 0x2b, 0xf0, 0xb6, 0x7c,
+ 0x47, 0x5f, 0xd1, 0x0a, 0x2c, 0xc4, 0xa5, 0x68,
+ 0xd0, 0x43, 0x75, 0x6b, 0x65, 0xaa, 0x32, 0xc6,
+ 0x99, 0x06, 0xcb, 0x8f, 0xe6, 0x8d, 0xce, 0xbf,
+ 0x4d, 0x0d, 0x7b, 0x22, 0x2a, 0x8a, 0xcb, 0x7d,
+ 0x7f, 0x16, 0x48, 0x85, 0xf1, 0x86, 0xcb, 0x54,
+ 0xb9, 0x39, 0xd4, 0xbc, 0xe3, 0x2d, 0x27, 0x59,
+ 0xf6, 0x81, 0x5e, 0x94, 0x45, 0xdf, 0xb9, 0x22,
+ 0xaf, 0x64, 0x0d, 0x14, 0xec, 0x8c, 0xeb, 0x71,
+ 0xac, 0xee, 0x09, 0x4c, 0xbf, 0x34, 0xf9, 0xf4,
+ 0x66, 0x77, 0x36, 0x3b, 0x41, 0x74, 0x01, 0x4f,
+ 0xfc, 0x56, 0x83, 0xba, 0x14, 0xb0, 0x2f, 0xdd,
+ 0x4d, 0xb9, 0x3f, 0xdf, 0x71, 0xbe, 0x7b, 0xba,
+ 0x66, 0xc8, 0xc5, 0x42, 0xc9, 0xba, 0x18, 0x63,
+ 0x45, 0x07, 0x2f, 0x84, 0x3e, 0xc3, 0xfb, 0x47,
+ 0xda, 0xd4, 0x1d, 0x0e, 0x9d, 0x96, 0xc0, 0xea,
+ 0xee, 0x45, 0x2f, 0xe1, 0x62, 0x23, 0xee, 0xef,
+ 0x3d, 0x5e, 0x55, 0xa1, 0x0d, 0x02, 0x81, 0x81,
+ 0x00, 0xeb, 0x76, 0x88, 0xd3, 0xae, 0x3f, 0x1d,
+ 0xf2, 0x49, 0xe0, 0x37, 0x49, 0x83, 0x82, 0x6c,
+ 0xf7, 0xf1, 0x17, 0x30, 0x75, 0x2e, 0x89, 0x06,
+ 0x88, 0x56, 0x32, 0xf6, 0xfa, 0x58, 0xcb, 0x3c,
+ 0x98, 0x67, 0xc3, 0xde, 0x10, 0x82, 0xe5, 0xfa,
+ 0xfa, 0x52, 0x47, 0x8d, 0xd7, 0x00, 0xc6, 0xcb,
+ 0xf7, 0xf6, 0x57, 0x9b, 0x6e, 0x0c, 0xac, 0xe8,
+ 0x3b, 0xd1, 0xde, 0xb5, 0x34, 0xaf, 0x8b, 0x2a,
+ 0xb0, 0x2d, 0x01, 0xeb, 0x7c, 0xa0, 0x42, 0x26,
+ 0xbb, 0x2b, 0x43, 0x0e, 0x1d, 0xe2, 0x4e, 0xc9,
+ 0xc1, 0x0a, 0x67, 0x1d, 0xfc, 0x83, 0x25, 0xce,
+ 0xb2, 0x18, 0xd9, 0x0d, 0x70, 0xf5, 0xa3, 0x5a,
+ 0x9c, 0x99, 0xdd, 0x47, 0xa1, 0x57, 0xe7, 0x20,
+ 0xde, 0xa1, 0x29, 0x8d, 0x96, 0x62, 0xf9, 0x26,
+ 0x95, 0x51, 0xa6, 0xe7, 0x09, 0x8b, 0xba, 0x16,
+ 0x8b, 0x19, 0x5b, 0xf9, 0x27, 0x0d, 0xc5, 0xd6,
+ 0x5f, 0x02, 0x81, 0x81, 0x00, 0xce, 0x26, 0x31,
+ 0xb5, 0x43, 0x53, 0x95, 0x39, 0xdd, 0x01, 0x98,
+ 0x8b, 0x3d, 0x27, 0xeb, 0x0b, 0x87, 0x1c, 0x95,
+ 0xfc, 0x3e, 0x36, 0x51, 0x31, 0xb5, 0xea, 0x59,
+ 0x56, 0xc0, 0x97, 0x62, 0xf0, 0x63, 0x2b, 0xb6,
+ 0x30, 0x9b, 0xdf, 0x19, 0x10, 0xe9, 0xa0, 0x3d,
+ 0xea, 0x54, 0x5a, 0xe6, 0xc6, 0x9e, 0x7e, 0xb5,
+ 0xf0, 0xb0, 0x54, 0xef, 0xc3, 0xe1, 0x47, 0xa6,
+ 0x95, 0xc7, 0xe4, 0xa3, 0x4a, 0x30, 0x68, 0x24,
+ 0x98, 0x7d, 0xc1, 0x34, 0xa9, 0xcb, 0xbc, 0x3c,
+ 0x08, 0x9c, 0x7d, 0x0c, 0xa2, 0xb7, 0x60, 0xaa,
+ 0x38, 0x08, 0x16, 0xa6, 0x7f, 0xdb, 0xd2, 0xb1,
+ 0x67, 0xe7, 0x93, 0x8e, 0xbb, 0x7e, 0xb9, 0xb5,
+ 0xd0, 0xd0, 0x9f, 0x7b, 0xcc, 0x46, 0xe6, 0x74,
+ 0x78, 0x1a, 0x96, 0xd6, 0xd7, 0x74, 0x34, 0x54,
+ 0x3b, 0x54, 0x55, 0x7f, 0x89, 0x81, 0xbc, 0x40,
+ 0x55, 0x87, 0x24, 0x95, 0x33, 0x02, 0x81, 0x81,
+ 0x00, 0xb0, 0x18, 0x5d, 0x2a, 0x1a, 0x95, 0x9f,
+ 0x9a, 0xd5, 0x3f, 0x37, 0x79, 0xe6, 0x3d, 0x83,
+ 0xab, 0x46, 0x86, 0x36, 0x3a, 0x5d, 0x0c, 0x23,
+ 0x73, 0x91, 0x2b, 0xda, 0x63, 0xce, 0x46, 0x68,
+ 0xd1, 0xfe, 0x40, 0x90, 0xf2, 0x3e, 0x43, 0x2b,
+ 0x19, 0x4c, 0xb1, 0xb0, 0xd5, 0x8c, 0x02, 0x21,
+ 0x07, 0x18, 0x17, 0xda, 0xe9, 0x49, 0xd7, 0x82,
+ 0x73, 0x42, 0x78, 0xd1, 0x82, 0x4e, 0x8a, 0xc0,
+ 0xe9, 0x33, 0x2f, 0xcd, 0x62, 0xce, 0x23, 0xca,
+ 0xfd, 0x8d, 0xd4, 0x3f, 0x59, 0x80, 0x27, 0xb6,
+ 0x61, 0x85, 0x9b, 0x2a, 0xe4, 0xef, 0x5c, 0x36,
+ 0x22, 0x21, 0xcd, 0x2a, 0x6d, 0x41, 0x77, 0xe2,
+ 0xcb, 0x5d, 0x93, 0x0d, 0x00, 0x10, 0x52, 0x8d,
+ 0xd5, 0x92, 0x28, 0x16, 0x78, 0xd3, 0x1a, 0x4c,
+ 0x8d, 0xbd, 0x9c, 0x1a, 0x0b, 0x9c, 0x91, 0x16,
+ 0x4c, 0xff, 0x31, 0x36, 0xbb, 0xcb, 0x64, 0x1a,
+ 0xf7, 0x02, 0x81, 0x80, 0x32, 0x65, 0x09, 0xdf,
+ 0xca, 0xee, 0xa2, 0xdb, 0x3b, 0x58, 0xc9, 0x86,
+ 0xb8, 0x53, 0x8a, 0xd5, 0x0d, 0x99, 0x82, 0x5c,
+ 0xe0, 0x84, 0x7c, 0xc2, 0xcf, 0x3a, 0xd3, 0xce,
+ 0x2e, 0x54, 0x93, 0xbe, 0x3a, 0x30, 0x14, 0x60,
+ 0xbb, 0xaa, 0x05, 0x41, 0xaa, 0x2b, 0x1f, 0x17,
+ 0xaa, 0xb9, 0x72, 0x12, 0xf9, 0xe9, 0xf5, 0xe6,
+ 0x39, 0xe4, 0xf9, 0x9c, 0x03, 0xf5, 0x75, 0x16,
+ 0xc6, 0x7f, 0xf1, 0x1f, 0x10, 0xc8, 0x54, 0xb1,
+ 0xe6, 0x84, 0x15, 0xb0, 0xb0, 0x7a, 0x7a, 0x9e,
+ 0x8c, 0x4a, 0xd1, 0x8c, 0xf1, 0x91, 0x32, 0xeb,
+ 0x71, 0xa6, 0xbf, 0xdb, 0x1f, 0xcc, 0xd8, 0xcb,
+ 0x92, 0xc3, 0xf2, 0xaf, 0x89, 0x22, 0x32, 0xfd,
+ 0x32, 0x12, 0xda, 0xbb, 0xac, 0x55, 0x68, 0x01,
+ 0x78, 0x56, 0x89, 0x7c, 0xb0, 0x0e, 0x9e, 0xcc,
+ 0xc6, 0x28, 0x04, 0x7e, 0x83, 0xf5, 0x96, 0x30,
+ 0x92, 0x51, 0xf2, 0x1b, 0x02, 0x81, 0x81, 0x00,
+ 0x83, 0x6d, 0xd1, 0x98, 0x90, 0x41, 0x8c, 0xa7,
+ 0x92, 0x83, 0xac, 0x89, 0x05, 0x0c, 0x79, 0x67,
+ 0x90, 0xb6, 0xa1, 0xf3, 0x2f, 0xca, 0xf0, 0x15,
+ 0xe0, 0x30, 0x58, 0xe9, 0x4f, 0xcb, 0x4c, 0x56,
+ 0x56, 0x56, 0x14, 0x3f, 0x1b, 0x79, 0xb6, 0xef,
+ 0x57, 0x4b, 0x28, 0xbd, 0xb0, 0xe6, 0x0c, 0x49,
+ 0x4b, 0xbe, 0xe1, 0x57, 0x28, 0x2a, 0x23, 0x5e,
+ 0xc4, 0xa2, 0x19, 0x4b, 0x00, 0x67, 0x78, 0xd9,
+ 0x26, 0x6e, 0x17, 0x25, 0xce, 0xe4, 0xfd, 0xde,
+ 0x86, 0xa8, 0x5a, 0x67, 0x47, 0x6b, 0x15, 0x09,
+ 0xe1, 0xec, 0x8e, 0x62, 0x98, 0x91, 0x6f, 0xc0,
+ 0x98, 0x0c, 0x70, 0x0e, 0x7d, 0xbe, 0x63, 0xbd,
+ 0x12, 0x5a, 0x98, 0x1c, 0xe3, 0x0c, 0xfb, 0xc7,
+ 0xfb, 0x1b, 0xbd, 0x02, 0x87, 0xcc, 0x0c, 0xbb,
+ 0xc2, 0xd4, 0xb6, 0xc1, 0xa1, 0x23, 0xd3, 0x1e,
+ 0x21, 0x6f, 0x48, 0xba, 0x0e, 0x2e, 0xc7, 0x42
+};
+
+static const uint8_t rsa4096_priv_key[] = {
+ 0x30, 0x82, 0x09, 0x29, 0x02, 0x01, 0x00, 0x02,
+ 0x82, 0x02, 0x01, 0x00, 0xcc, 0x30, 0xc6, 0x90,
+ 0x49, 0x2b, 0x86, 0xe7, 0x7a, 0xa5, 0x7a, 0x9a,
+ 0x4f, 0xee, 0x0e, 0xa1, 0x5c, 0x43, 0x64, 0xd0,
+ 0x76, 0xe1, 0xfd, 0x0b, 0xfd, 0x43, 0x7a, 0x65,
+ 0xe6, 0x20, 0xbd, 0xf2, 0x0e, 0xbe, 0x76, 0x54,
+ 0xae, 0x37, 0xbe, 0xa0, 0x02, 0x96, 0xae, 0x8d,
+ 0x8a, 0xae, 0x3b, 0x88, 0xbb, 0x67, 0xce, 0x7c,
+ 0x20, 0xbf, 0x14, 0xc3, 0x71, 0x51, 0x87, 0x03,
+ 0x34, 0xaa, 0x3c, 0x09, 0xff, 0xe9, 0xeb, 0xb7,
+ 0x85, 0x5c, 0xbb, 0x8d, 0xce, 0x8e, 0x3f, 0xd1,
+ 0x16, 0x30, 0x00, 0x32, 0x2f, 0x25, 0x8d, 0xef,
+ 0x71, 0xd9, 0xea, 0x6b, 0x45, 0x53, 0x49, 0xc3,
+ 0x09, 0x4f, 0xb0, 0xa8, 0xa5, 0x89, 0x76, 0x59,
+ 0x31, 0xa5, 0xf1, 0x5c, 0x42, 0x54, 0x57, 0x70,
+ 0x57, 0xad, 0xd8, 0xeb, 0x89, 0xa6, 0x87, 0xa2,
+ 0x6c, 0x95, 0x58, 0x8f, 0xb6, 0x82, 0xc7, 0xde,
+ 0xc2, 0x3a, 0xdc, 0x5b, 0xe8, 0x02, 0xcc, 0x26,
+ 0x4b, 0x01, 0xaa, 0xe6, 0xf3, 0x66, 0x4d, 0x90,
+ 0x85, 0xde, 0xf4, 0x5d, 0x80, 0x98, 0xc6, 0x65,
+ 0xcf, 0x44, 0x4c, 0xde, 0xb5, 0x4a, 0xfc, 0xda,
+ 0x0a, 0x0a, 0x10, 0x26, 0xa3, 0xcb, 0x9d, 0xe4,
+ 0x8d, 0xab, 0x2c, 0x04, 0xfd, 0xaa, 0xfc, 0x3b,
+ 0xac, 0x4e, 0x56, 0xb8, 0x4c, 0x9f, 0x22, 0x49,
+ 0xcb, 0x76, 0x45, 0x24, 0x36, 0x2d, 0xbb, 0xe6,
+ 0x7e, 0xa9, 0x93, 0x13, 0x96, 0x1e, 0xfc, 0x4b,
+ 0x75, 0xd4, 0x54, 0xc8, 0x8c, 0x55, 0xe6, 0x3f,
+ 0x09, 0x5a, 0x03, 0x74, 0x7c, 0x8a, 0xc8, 0xe7,
+ 0x49, 0x0b, 0x86, 0x7c, 0x97, 0xa0, 0xf2, 0x0d,
+ 0xf1, 0x5c, 0x0e, 0x7a, 0xc0, 0x3f, 0x78, 0x2d,
+ 0x9b, 0xe2, 0x26, 0xa0, 0x89, 0x49, 0x0c, 0xad,
+ 0x79, 0xa6, 0x82, 0x98, 0xa6, 0xb7, 0x74, 0xb4,
+ 0x45, 0xc8, 0xed, 0xea, 0x81, 0xcd, 0xf0, 0x3b,
+ 0x8e, 0x24, 0xfb, 0x0c, 0xd0, 0x3a, 0x14, 0xb9,
+ 0xb4, 0x3b, 0x69, 0xd9, 0xf2, 0x42, 0x6e, 0x7f,
+ 0x6f, 0x5e, 0xb1, 0x52, 0x5b, 0xaa, 0xef, 0xae,
+ 0x1e, 0x34, 0xca, 0xed, 0x0a, 0x8d, 0x56, 0xd6,
+ 0xdd, 0xd4, 0x2c, 0x54, 0x7a, 0x57, 0xca, 0x7e,
+ 0x4a, 0x11, 0xde, 0x48, 0xdf, 0x2b, 0x09, 0x97,
+ 0x39, 0x24, 0xce, 0x45, 0xe0, 0x75, 0xb1, 0x19,
+ 0x42, 0xdb, 0x63, 0x40, 0x9b, 0xb9, 0x95, 0x96,
+ 0x78, 0x91, 0xd5, 0x19, 0x12, 0xab, 0xef, 0x55,
+ 0x6f, 0x0d, 0x65, 0xc0, 0x8f, 0x62, 0x99, 0x78,
+ 0xc0, 0xe0, 0xe1, 0x33, 0xc7, 0x68, 0xff, 0x29,
+ 0x66, 0x22, 0x3a, 0x6f, 0xa0, 0xf8, 0x5c, 0x68,
+ 0x9b, 0xa9, 0x05, 0xad, 0x6b, 0x1d, 0xae, 0xc1,
+ 0x30, 0xbb, 0xfe, 0xb7, 0x31, 0x85, 0x0d, 0xd1,
+ 0xd5, 0xfc, 0x43, 0x1e, 0xb3, 0x61, 0x6f, 0xc4,
+ 0x75, 0xed, 0x76, 0x9d, 0x13, 0xb3, 0x61, 0x57,
+ 0xc8, 0x33, 0x0d, 0x77, 0x84, 0xf0, 0xc7, 0x62,
+ 0xb9, 0x9e, 0xd5, 0x01, 0xfa, 0x87, 0x4a, 0xf5,
+ 0xd7, 0x4f, 0x5d, 0xae, 0xe7, 0x08, 0xd2, 0x5a,
+ 0x65, 0x30, 0xc9, 0xf0, 0x0a, 0x11, 0xf1, 0x2a,
+ 0xd3, 0x43, 0x43, 0xca, 0x05, 0x90, 0x85, 0xf4,
+ 0xbc, 0x37, 0x49, 0x40, 0x45, 0x35, 0xd3, 0x56,
+ 0x06, 0x4c, 0x63, 0x93, 0x07, 0x14, 0x8b, 0xd3,
+ 0x12, 0xd0, 0xe5, 0x00, 0x48, 0x76, 0xd2, 0xdf,
+ 0x7c, 0xea, 0xc7, 0xff, 0xf0, 0x88, 0xd5, 0xa4,
+ 0x61, 0x7d, 0x79, 0xc2, 0xda, 0x53, 0x24, 0xdc,
+ 0x20, 0xae, 0xe6, 0x08, 0x65, 0xef, 0xc9, 0x0d,
+ 0x7d, 0x66, 0x6d, 0x1b, 0x1c, 0x5d, 0x46, 0xe1,
+ 0x26, 0x8a, 0x29, 0x77, 0x76, 0x19, 0xe5, 0x19,
+ 0x2a, 0x75, 0x21, 0xf1, 0x92, 0x8a, 0x9c, 0x7b,
+ 0xe8, 0x0b, 0x38, 0xc1, 0xbf, 0x76, 0x22, 0x45,
+ 0x4a, 0xd3, 0x43, 0xc3, 0x8c, 0x74, 0xd8, 0xd8,
+ 0xec, 0x3e, 0x14, 0xdf, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0x02, 0x82, 0x02, 0x01, 0x00, 0x9e, 0x13,
+ 0x64, 0xa5, 0x6e, 0xff, 0xf3, 0x80, 0x60, 0xc2,
+ 0x9b, 0x17, 0xbb, 0xa9, 0x60, 0x4a, 0x2b, 0x53,
+ 0x41, 0x48, 0xe1, 0xc0, 0x32, 0x56, 0x85, 0xcb,
+ 0x27, 0x86, 0x9b, 0x91, 0xdd, 0x7a, 0xf7, 0x4f,
+ 0x1b, 0xec, 0x92, 0xb3, 0x35, 0x30, 0x4a, 0xd0,
+ 0xbc, 0x71, 0x77, 0x5b, 0x4b, 0x5b, 0x9f, 0x39,
+ 0xcd, 0xf0, 0xea, 0xa9, 0x03, 0x3a, 0x0b, 0x10,
+ 0x42, 0xa5, 0x88, 0xb0, 0x01, 0xaa, 0xfc, 0x23,
+ 0xec, 0x08, 0x37, 0x86, 0x82, 0xec, 0x55, 0x6c,
+ 0x6a, 0x9b, 0x43, 0xc2, 0x05, 0x64, 0xd4, 0x7b,
+ 0x0e, 0x56, 0xc0, 0x9d, 0x23, 0x8d, 0xc8, 0x2d,
+ 0xa2, 0x7d, 0x0b, 0x48, 0x56, 0x4b, 0x39, 0x5c,
+ 0x21, 0xf3, 0x0b, 0x2c, 0x9c, 0x9d, 0xff, 0xfb,
+ 0xab, 0x75, 0x9d, 0x6b, 0x48, 0xf3, 0x8f, 0xad,
+ 0x0c, 0x74, 0x01, 0xfb, 0xdc, 0x83, 0xe5, 0x97,
+ 0x79, 0x84, 0x4a, 0x79, 0xa6, 0xfe, 0xbf, 0xae,
+ 0xea, 0xbc, 0xfa, 0x74, 0x60, 0x0a, 0x4b, 0x84,
+ 0x77, 0xa7, 0xda, 0xfb, 0xaf, 0xd2, 0x73, 0x2b,
+ 0xd2, 0xec, 0x1e, 0x79, 0x91, 0xc9, 0x18, 0x30,
+ 0xe5, 0x6f, 0x27, 0x36, 0x83, 0x2a, 0x66, 0xc3,
+ 0xcb, 0x88, 0x94, 0xe4, 0x5f, 0x3f, 0xbd, 0xe2,
+ 0x11, 0x43, 0x61, 0x31, 0x84, 0x91, 0x49, 0x40,
+ 0x29, 0x1b, 0x58, 0x18, 0x47, 0x8e, 0xb1, 0x22,
+ 0xd6, 0xc4, 0xaa, 0x6a, 0x3d, 0x22, 0x7c, 0xa5,
+ 0xa0, 0x4c, 0x0a, 0xfc, 0x46, 0x66, 0xbb, 0xbe,
+ 0x04, 0x71, 0xe8, 0x9b, 0x76, 0xf1, 0x47, 0x39,
+ 0x6a, 0x2f, 0x23, 0xad, 0x78, 0x80, 0x1c, 0x22,
+ 0xcd, 0x41, 0x5e, 0x09, 0x16, 0x6c, 0x91, 0x48,
+ 0x91, 0x91, 0x3d, 0x8c, 0xe6, 0xba, 0x81, 0x8d,
+ 0xbb, 0xf2, 0xd0, 0xaa, 0xc7, 0x8f, 0xc6, 0x01,
+ 0x60, 0xa7, 0xef, 0x1e, 0x8e, 0x91, 0x6d, 0xcc,
+ 0x30, 0x9e, 0xea, 0x7c, 0x56, 0x9d, 0x42, 0xcf,
+ 0x44, 0x85, 0x52, 0xa8, 0xf2, 0x36, 0x9c, 0x46,
+ 0xfa, 0x9d, 0xd3, 0x4e, 0x13, 0x46, 0x81, 0xce,
+ 0x99, 0xc9, 0x58, 0x47, 0xe4, 0xeb, 0x27, 0x56,
+ 0x29, 0x61, 0x0f, 0xb5, 0xcb, 0xf3, 0x48, 0x58,
+ 0x8f, 0xbc, 0xaf, 0x0a, 0xbf, 0x40, 0xd1, 0xf6,
+ 0x4f, 0xd2, 0x89, 0x4a, 0xff, 0x6f, 0x54, 0x70,
+ 0x49, 0x42, 0xf6, 0xf8, 0x0e, 0x4f, 0xa5, 0xf6,
+ 0x8b, 0x49, 0x80, 0xd4, 0xf5, 0x03, 0xf8, 0x65,
+ 0xe7, 0x1f, 0x0a, 0xc0, 0x8f, 0xd3, 0x7a, 0x70,
+ 0xca, 0x67, 0xaf, 0x71, 0xfd, 0x4b, 0xe1, 0x17,
+ 0x76, 0x74, 0x2e, 0x12, 0x7b, 0xad, 0x4b, 0xbb,
+ 0xd2, 0x64, 0xd0, 0xa9, 0xf9, 0x79, 0xa9, 0xa6,
+ 0x03, 0xd2, 0xc2, 0x8f, 0x47, 0x59, 0x1b, 0x7c,
+ 0xe3, 0xce, 0x92, 0xb2, 0xac, 0x3e, 0xee, 0x12,
+ 0x43, 0x5f, 0x23, 0xec, 0xf1, 0xd3, 0xf2, 0x21,
+ 0x22, 0xe8, 0x7e, 0x7f, 0xa4, 0x93, 0x8e, 0x78,
+ 0x69, 0x69, 0xa0, 0xc9, 0xce, 0x86, 0x36, 0x13,
+ 0x10, 0x21, 0xc4, 0x7a, 0x52, 0xcf, 0x53, 0xd9,
+ 0x9b, 0x58, 0xe6, 0x2d, 0xeb, 0x60, 0xe3, 0x75,
+ 0x1a, 0x22, 0xf6, 0x3c, 0x54, 0x6b, 0xfa, 0xa1,
+ 0x5d, 0xf6, 0x38, 0xf0, 0xd4, 0x26, 0x2d, 0x7d,
+ 0x74, 0x99, 0x6a, 0x13, 0x8a, 0x07, 0x9f, 0x07,
+ 0xc5, 0xf4, 0xa8, 0x20, 0x11, 0xa9, 0x76, 0x11,
+ 0xe4, 0x48, 0xae, 0xa4, 0x8a, 0xa1, 0xbf, 0x1f,
+ 0xba, 0x37, 0x50, 0x53, 0x43, 0x91, 0x45, 0x88,
+ 0x03, 0x52, 0xba, 0xac, 0xc8, 0xe3, 0xe1, 0xba,
+ 0x63, 0x24, 0x72, 0xbe, 0x1d, 0x01, 0x1f, 0x6c,
+ 0x34, 0x10, 0xb8, 0x56, 0x4a, 0x67, 0x28, 0x4b,
+ 0x7a, 0x2b, 0x31, 0x29, 0x47, 0xda, 0xdf, 0x53,
+ 0x88, 0x79, 0x22, 0x31, 0x15, 0x56, 0xe3, 0xa0,
+ 0x79, 0x75, 0x94, 0x90, 0xb2, 0xe8, 0x4b, 0xca,
+ 0x82, 0x6d, 0x3c, 0x69, 0x43, 0x01, 0x02, 0x82,
+ 0x01, 0x01, 0x00, 0xe7, 0x8b, 0xd6, 0x1a, 0xe8,
+ 0x00, 0xed, 0x9d, 0x7c, 0x5a, 0x32, 0x10, 0xc1,
+ 0x53, 0x50, 0xbe, 0x27, 0x1d, 0xef, 0x69, 0x73,
+ 0xa2, 0x8f, 0x95, 0x96, 0x86, 0xfe, 0xfb, 0x82,
+ 0xdb, 0xea, 0x7d, 0x73, 0x5a, 0x2b, 0xe7, 0x4b,
+ 0xd5, 0x8f, 0x4f, 0xaf, 0x85, 0x1d, 0x15, 0x1a,
+ 0x58, 0x5f, 0x41, 0x79, 0x70, 0x5c, 0x8f, 0xa9,
+ 0x8e, 0x23, 0x31, 0xa7, 0x6d, 0x99, 0x0c, 0xf0,
+ 0x51, 0xbf, 0xbb, 0xd3, 0xe3, 0xa3, 0x34, 0xf0,
+ 0x1d, 0x7f, 0x4a, 0xb7, 0x8f, 0xf6, 0x0a, 0x49,
+ 0x65, 0xaf, 0x35, 0x7b, 0x02, 0x2e, 0x69, 0x49,
+ 0x95, 0xb5, 0x20, 0x70, 0xb2, 0x98, 0x54, 0x9b,
+ 0x8e, 0x4f, 0x48, 0xa8, 0xfa, 0x7e, 0xc7, 0x0a,
+ 0xae, 0x84, 0xe1, 0xba, 0x85, 0x98, 0x96, 0x8a,
+ 0x7c, 0xdd, 0xcc, 0xcd, 0xd8, 0x5b, 0x50, 0x60,
+ 0x88, 0x2d, 0xb6, 0x3e, 0xb8, 0xc2, 0xae, 0xa5,
+ 0x62, 0x10, 0xcd, 0xdc, 0xae, 0x86, 0xfe, 0x31,
+ 0x8b, 0xf7, 0xee, 0x1a, 0x35, 0x46, 0x83, 0xee,
+ 0x5f, 0x55, 0x9a, 0xc2, 0xca, 0x53, 0xb7, 0x2c,
+ 0xbf, 0x03, 0x8a, 0x78, 0xcc, 0x1d, 0x96, 0x7b,
+ 0xac, 0x00, 0x62, 0x1e, 0xbd, 0x6f, 0x0b, 0xa5,
+ 0xec, 0xf3, 0x02, 0x47, 0x47, 0x1e, 0x3d, 0xf6,
+ 0x78, 0x42, 0xe4, 0xcd, 0xf8, 0x14, 0xa3, 0x7d,
+ 0xd5, 0x2f, 0x6e, 0xcc, 0x1a, 0x9e, 0xe7, 0xcf,
+ 0x48, 0xb9, 0x80, 0xb8, 0xba, 0xaa, 0x7b, 0xae,
+ 0x65, 0x74, 0x09, 0x7b, 0x43, 0x26, 0x31, 0xa2,
+ 0x95, 0x43, 0x69, 0xd0, 0xb7, 0x95, 0xe4, 0x76,
+ 0x2c, 0x42, 0x19, 0x47, 0x4f, 0x63, 0x35, 0x9c,
+ 0xa2, 0x1a, 0xce, 0x28, 0xdf, 0x76, 0x98, 0x1d,
+ 0xd4, 0x2e, 0xf6, 0x3a, 0xc8, 0x3e, 0xc7, 0xaf,
+ 0xf7, 0x38, 0x3f, 0x83, 0x3a, 0xcb, 0xae, 0x41,
+ 0x75, 0x46, 0x63, 0xaa, 0x45, 0xb1, 0x2c, 0xd9,
+ 0x9f, 0x17, 0x37, 0x02, 0x82, 0x01, 0x01, 0x00,
+ 0xe1, 0xc1, 0x57, 0x4d, 0x0f, 0xa5, 0xea, 0x1d,
+ 0x39, 0x9c, 0xe0, 0xf0, 0x6d, 0x13, 0x7f, 0x79,
+ 0xdc, 0x72, 0x61, 0xc0, 0x7f, 0x88, 0xf6, 0x38,
+ 0x4f, 0x49, 0x06, 0x1e, 0xb8, 0x6c, 0x21, 0x04,
+ 0x60, 0x76, 0x5a, 0x6d, 0x04, 0xd1, 0x6d, 0xac,
+ 0x7c, 0x25, 0x4f, 0x32, 0xcb, 0xbc, 0xf8, 0x4a,
+ 0x22, 0x8f, 0xf5, 0x41, 0xfd, 0x1c, 0x76, 0x30,
+ 0xc2, 0x5f, 0x99, 0x13, 0x5c, 0x57, 0x0f, 0xfd,
+ 0xac, 0x0b, 0x10, 0x9a, 0x4f, 0x78, 0x0a, 0x86,
+ 0xe8, 0x07, 0x40, 0x40, 0x13, 0xba, 0x96, 0x07,
+ 0xd5, 0x39, 0x91, 0x51, 0x3e, 0x80, 0xd8, 0xa0,
+ 0x1f, 0xff, 0xdc, 0x9e, 0x09, 0x3b, 0xae, 0x38,
+ 0xa9, 0xc2, 0x14, 0x7b, 0xee, 0xd2, 0x69, 0x3d,
+ 0xd6, 0x26, 0x74, 0x72, 0x7b, 0x86, 0xd4, 0x13,
+ 0x5b, 0xb8, 0x76, 0x4b, 0x08, 0xfb, 0x93, 0xfa,
+ 0x44, 0xaf, 0x98, 0x3b, 0xfa, 0xd0, 0x2a, 0x04,
+ 0x8b, 0xb3, 0x3c, 0x6d, 0x32, 0xf7, 0x18, 0x6a,
+ 0x51, 0x0e, 0x40, 0x90, 0xce, 0x8e, 0xdf, 0xe8,
+ 0x07, 0x4c, 0x0f, 0xc7, 0xc8, 0xc2, 0x18, 0x58,
+ 0x6a, 0x01, 0xc8, 0x27, 0xd6, 0x43, 0x2a, 0xfb,
+ 0xa5, 0x34, 0x01, 0x3c, 0x72, 0xb1, 0x48, 0xce,
+ 0x2b, 0x9b, 0xb4, 0x69, 0xd9, 0x82, 0xf8, 0xbe,
+ 0x29, 0x88, 0x75, 0x96, 0xd8, 0xef, 0x78, 0x2a,
+ 0x07, 0x90, 0xa0, 0x56, 0x33, 0x42, 0x05, 0x19,
+ 0xb0, 0x69, 0x34, 0xf9, 0x03, 0xc5, 0xa8, 0x0d,
+ 0x72, 0xa2, 0x27, 0xb4, 0x45, 0x6d, 0xd2, 0x01,
+ 0x6c, 0xf1, 0x74, 0x51, 0x0a, 0x9a, 0xe2, 0xc1,
+ 0x96, 0x80, 0x30, 0x0e, 0xc6, 0xa9, 0x79, 0xf7,
+ 0x6f, 0xaf, 0xf6, 0xe8, 0x2a, 0xcc, 0xbd, 0xad,
+ 0x8f, 0xe0, 0x32, 0x87, 0x85, 0x49, 0x68, 0x88,
+ 0x15, 0x5c, 0xdb, 0x48, 0x40, 0xa2, 0xfa, 0x42,
+ 0xe8, 0x4e, 0x3e, 0xe2, 0x3f, 0xe0, 0xf3, 0x99,
+ 0x02, 0x82, 0x01, 0x00, 0x08, 0x39, 0x97, 0x69,
+ 0x6d, 0x44, 0x5b, 0x2c, 0x74, 0xf6, 0x5f, 0x40,
+ 0xe9, 0x1d, 0x24, 0x89, 0x1c, 0xaa, 0x9b, 0x8e,
+ 0x8b, 0x65, 0x02, 0xe4, 0xb5, 0x6c, 0x26, 0x32,
+ 0x98, 0xfb, 0x66, 0xe0, 0xfd, 0xef, 0xfe, 0x0f,
+ 0x41, 0x4a, 0x5c, 0xc4, 0xdf, 0xdf, 0x42, 0xa1,
+ 0x35, 0x46, 0x5e, 0x5b, 0xdd, 0x0c, 0x78, 0xbd,
+ 0x41, 0xb0, 0xa2, 0xdf, 0x68, 0xab, 0x23, 0xfc,
+ 0xa9, 0xac, 0xbd, 0xba, 0xd6, 0x54, 0x07, 0xc0,
+ 0x21, 0xa7, 0x6a, 0x96, 0x24, 0xdf, 0x20, 0x46,
+ 0x4d, 0x45, 0x27, 0x6c, 0x26, 0xea, 0x74, 0xeb,
+ 0x98, 0x89, 0x90, 0xdd, 0x8e, 0x23, 0x49, 0xf5,
+ 0xf7, 0x70, 0x9e, 0xb0, 0x5e, 0x10, 0x47, 0xe0,
+ 0x9a, 0x28, 0x88, 0xdf, 0xdb, 0xd8, 0x53, 0x0b,
+ 0x45, 0xf0, 0x19, 0x90, 0xe4, 0xdf, 0x02, 0x9f,
+ 0x60, 0x4e, 0x76, 0x11, 0x3b, 0x39, 0x24, 0xf1,
+ 0x3f, 0x3e, 0xb4, 0x8a, 0x1b, 0x84, 0xb7, 0x96,
+ 0xdf, 0xfb, 0xb0, 0xda, 0xec, 0x63, 0x68, 0x15,
+ 0xd7, 0xa9, 0xdb, 0x48, 0x9c, 0x12, 0xc3, 0xd6,
+ 0x85, 0xe8, 0x63, 0x1f, 0xd0, 0x1a, 0xb0, 0x12,
+ 0x60, 0x62, 0x43, 0xc1, 0x38, 0x86, 0x52, 0x23,
+ 0x7f, 0xc9, 0x62, 0xf8, 0x79, 0xbf, 0xb4, 0xfb,
+ 0x4e, 0x7e, 0x07, 0x22, 0x49, 0x8e, 0xbe, 0x6c,
+ 0xf0, 0x53, 0x5a, 0x53, 0xfd, 0x3c, 0x14, 0xd8,
+ 0xf7, 0x2c, 0x06, 0x2a, 0xe4, 0x64, 0xfd, 0x19,
+ 0x57, 0xa0, 0x92, 0xf6, 0xa3, 0x42, 0x47, 0x61,
+ 0x0b, 0xfd, 0x71, 0x5f, 0x98, 0xe2, 0x6c, 0x98,
+ 0xa8, 0xf9, 0xf9, 0x7f, 0x1c, 0x61, 0x5d, 0x8c,
+ 0xd1, 0xfb, 0x90, 0x28, 0x32, 0x9b, 0x7d, 0x82,
+ 0xf9, 0xcc, 0x47, 0xbe, 0xc7, 0x67, 0xc5, 0x93,
+ 0x22, 0x55, 0x0d, 0xd2, 0x73, 0xbe, 0xea, 0xed,
+ 0x4d, 0xb5, 0xf4, 0xc2, 0x25, 0x92, 0x44, 0x30,
+ 0xeb, 0xaa, 0x13, 0x11, 0x02, 0x82, 0x01, 0x01,
+ 0x00, 0x82, 0x42, 0x02, 0x53, 0x4e, 0x72, 0x16,
+ 0xf1, 0x21, 0xea, 0xe8, 0xc7, 0x10, 0xc8, 0xad,
+ 0x46, 0xec, 0xf1, 0x7a, 0x81, 0x8d, 0x94, 0xc3,
+ 0x2c, 0x9e, 0x62, 0xae, 0x0b, 0x4f, 0xb1, 0xe4,
+ 0x23, 0x18, 0x5d, 0x71, 0xb3, 0x71, 0x92, 0x3d,
+ 0x4b, 0xc6, 0x9d, 0xe8, 0x62, 0x90, 0xb7, 0xca,
+ 0x33, 0x4c, 0x59, 0xef, 0xd3, 0x51, 0x6d, 0xf8,
+ 0xac, 0x0d, 0x9b, 0x07, 0x41, 0xea, 0x87, 0xb9,
+ 0x8c, 0x4e, 0x96, 0x5b, 0xd0, 0x0d, 0x86, 0x5f,
+ 0xdc, 0x93, 0x48, 0x8b, 0xc3, 0xed, 0x1e, 0x3d,
+ 0xae, 0xeb, 0x52, 0xba, 0x0c, 0x3c, 0x9a, 0x2f,
+ 0x63, 0xc4, 0xd2, 0xe6, 0xc2, 0xb0, 0xe5, 0x24,
+ 0x93, 0x41, 0x2f, 0xe0, 0x8d, 0xd9, 0xb0, 0xc2,
+ 0x54, 0x91, 0x99, 0xc2, 0x9a, 0xc3, 0xb7, 0x79,
+ 0xea, 0x69, 0x83, 0xb7, 0x8d, 0x77, 0xf3, 0x60,
+ 0xe0, 0x88, 0x7d, 0x20, 0xc3, 0x8a, 0xe6, 0x4d,
+ 0x38, 0x2e, 0x3b, 0x0e, 0xe4, 0x9b, 0x01, 0x83,
+ 0xae, 0xe4, 0x71, 0xea, 0xc3, 0x22, 0xcb, 0xc1,
+ 0x59, 0xa9, 0xcc, 0x33, 0x56, 0xbc, 0xf9, 0x70,
+ 0xfe, 0xa2, 0xbb, 0xc0, 0x77, 0x6b, 0xe3, 0x79,
+ 0x8b, 0x95, 0x38, 0xba, 0x75, 0xdc, 0x5f, 0x7a,
+ 0x78, 0xab, 0x24, 0xbe, 0x26, 0x4d, 0x00, 0x8a,
+ 0xf1, 0x7e, 0x19, 0x64, 0x6f, 0xd3, 0x5f, 0xe8,
+ 0xdf, 0xa7, 0x59, 0xc5, 0x89, 0xb7, 0x2d, 0xa2,
+ 0xaf, 0xbd, 0xe0, 0x16, 0x56, 0x8f, 0xdc, 0x9e,
+ 0x28, 0x94, 0x3a, 0x07, 0xda, 0xb6, 0x2c, 0xb5,
+ 0x7d, 0x69, 0x14, 0xb0, 0x5e, 0x8a, 0x55, 0xef,
+ 0xfc, 0x6f, 0x10, 0x2b, 0xaa, 0x7a, 0xea, 0x12,
+ 0x9b, 0xb8, 0x6f, 0xb9, 0x71, 0x20, 0x30, 0xde,
+ 0x48, 0xa4, 0xb9, 0x61, 0xae, 0x5c, 0x33, 0x8d,
+ 0x02, 0xe8, 0x00, 0x99, 0xed, 0xc8, 0x8d, 0xc1,
+ 0x04, 0x95, 0xf1, 0x7f, 0xcb, 0x1f, 0xbc, 0x76,
+ 0x11, 0x02, 0x82, 0x01, 0x00, 0x2d, 0x0c, 0xa9,
+ 0x8f, 0x11, 0xc2, 0xf3, 0x02, 0xc8, 0xf2, 0x55,
+ 0xc5, 0x6d, 0x25, 0x88, 0xba, 0x59, 0xf6, 0xd1,
+ 0xdb, 0x94, 0x2f, 0x0b, 0x65, 0x2c, 0xad, 0x54,
+ 0xe0, 0x2b, 0xe6, 0xa3, 0x49, 0xa2, 0xb3, 0xca,
+ 0xd7, 0xec, 0x27, 0x32, 0xbb, 0xa4, 0x16, 0x90,
+ 0xbb, 0x67, 0xad, 0x1b, 0xb9, 0x0f, 0x78, 0xcb,
+ 0xad, 0x5c, 0xc3, 0x66, 0xd6, 0xbb, 0x97, 0x28,
+ 0x01, 0x31, 0xf9, 0x0f, 0x71, 0x2a, 0xb9, 0x5b,
+ 0xea, 0x34, 0x49, 0x9c, 0x6b, 0x13, 0x40, 0x65,
+ 0xbd, 0x18, 0x0a, 0x14, 0xf9, 0x33, 0x47, 0xe8,
+ 0x9f, 0x64, 0x0e, 0x24, 0xf6, 0xbb, 0x90, 0x23,
+ 0x66, 0x01, 0xa6, 0xa4, 0xa9, 0x7f, 0x64, 0x51,
+ 0xa3, 0x8a, 0x73, 0xc1, 0x80, 0xaf, 0x7a, 0x49,
+ 0x75, 0x5d, 0x56, 0x1c, 0xaa, 0x3f, 0x64, 0xa9,
+ 0x96, 0xfd, 0xb0, 0x90, 0xc5, 0xe0, 0x3d, 0x36,
+ 0x05, 0xad, 0xad, 0x84, 0x93, 0x84, 0xab, 0x1b,
+ 0x34, 0x57, 0x39, 0xae, 0x0e, 0x80, 0x0f, 0x4a,
+ 0x9b, 0x32, 0x56, 0xbd, 0x30, 0xeb, 0xd1, 0xc8,
+ 0xc4, 0x9f, 0x9c, 0x07, 0xb6, 0x05, 0xb1, 0x21,
+ 0x7f, 0x69, 0x92, 0x9f, 0xb7, 0x68, 0xe7, 0xde,
+ 0xb7, 0xbc, 0xb4, 0x89, 0x5b, 0x1c, 0x1b, 0x48,
+ 0xd1, 0x44, 0x6e, 0xd7, 0x6b, 0xe2, 0xa1, 0xf4,
+ 0xbf, 0x17, 0xb4, 0x43, 0x70, 0x26, 0xd4, 0xb9,
+ 0xf5, 0x19, 0x09, 0x08, 0xe9, 0xa3, 0x49, 0x7d,
+ 0x2f, 0xdc, 0xe8, 0x75, 0x79, 0xa1, 0xc1, 0x70,
+ 0x1b, 0x60, 0x97, 0xaf, 0x0c, 0x56, 0x68, 0xac,
+ 0x0e, 0x53, 0xbe, 0x56, 0xf4, 0xc3, 0xb1, 0xfb,
+ 0xfb, 0xff, 0x73, 0x5b, 0xa7, 0xf6, 0x99, 0x0e,
+ 0x14, 0x5a, 0x5f, 0x9d, 0xbd, 0x8e, 0x94, 0xec,
+ 0x8b, 0x38, 0x72, 0xbc, 0x8b, 0xca, 0x32, 0xa8,
+ 0x39, 0x43, 0xb1, 0x1d, 0x43, 0x29, 0xbe, 0x60,
+ 0xdb, 0x91, 0x6c, 0x9c, 0x06,
+};
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index a8af85128d..80ca622680 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -78,6 +78,7 @@ if have_block
'test-crypto-hash': [crypto],
'test-crypto-hmac': [crypto],
'test-crypto-cipher': [crypto],
+ 'test-crypto-akcipher': [crypto],
'test-crypto-secret': [crypto, keyutils],
'test-authz-simple': [authz],
'test-authz-list': [authz],
diff --git a/tests/unit/test-crypto-akcipher.c b/tests/unit/test-crypto-akcipher.c
new file mode 100644
index 0000000000..b5be563884
--- /dev/null
+++ b/tests/unit/test-crypto-akcipher.c
@@ -0,0 +1,711 @@
+/*
+ * QEMU Crypto cipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "crypto/init.h"
+#include "crypto/akcipher.h"
+#include "qapi/error.h"
+
+static const uint8_t rsa1024_private_key[] = {
+ 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02,
+ 0x81, 0x81, 0x00, 0xe6, 0x4d, 0x76, 0x4f, 0xb2,
+ 0x97, 0x09, 0xad, 0x9d, 0x17, 0x33, 0xf2, 0x30,
+ 0x42, 0x83, 0xa9, 0xcb, 0x49, 0xa4, 0x2e, 0x59,
+ 0x5e, 0x75, 0x51, 0xd1, 0xac, 0xc8, 0x86, 0x3e,
+ 0xdb, 0x72, 0x2e, 0xb2, 0xf7, 0xc3, 0x5b, 0xc7,
+ 0xea, 0xed, 0x30, 0xd1, 0xf7, 0x37, 0xee, 0x9d,
+ 0x36, 0x59, 0x6f, 0xf8, 0xce, 0xc0, 0x5c, 0x82,
+ 0x80, 0x37, 0x83, 0xd7, 0x45, 0x6a, 0xe9, 0xea,
+ 0xc5, 0x3a, 0x59, 0x6b, 0x34, 0x31, 0x44, 0x00,
+ 0x74, 0xa7, 0x29, 0xab, 0x79, 0x4a, 0xbd, 0xe8,
+ 0x25, 0x35, 0x01, 0x11, 0x40, 0xbf, 0x31, 0xbd,
+ 0xd3, 0xe0, 0x68, 0x1e, 0xd5, 0x5b, 0x2f, 0xe9,
+ 0x20, 0xf2, 0x9f, 0x46, 0x35, 0x30, 0xa8, 0xf1,
+ 0xfe, 0xef, 0xd8, 0x76, 0x23, 0x46, 0x34, 0x70,
+ 0xa1, 0xce, 0xc6, 0x65, 0x6d, 0xb0, 0x94, 0x7e,
+ 0xe5, 0x92, 0x45, 0x7b, 0xaa, 0xbb, 0x95, 0x97,
+ 0x77, 0xcd, 0xd3, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x02, 0x81, 0x80, 0x30, 0x6a, 0xc4, 0x9e, 0xc8,
+ 0xba, 0xfc, 0x2b, 0xe5, 0xc4, 0xc5, 0x04, 0xfb,
+ 0xa4, 0x60, 0x2d, 0xc8, 0x31, 0x39, 0x35, 0x0d,
+ 0x50, 0xd0, 0x75, 0x5d, 0x11, 0x68, 0x2e, 0xe0,
+ 0xf4, 0x1d, 0xb3, 0x37, 0xa8, 0xe3, 0x07, 0x5e,
+ 0xa6, 0x43, 0x2b, 0x6a, 0x59, 0x01, 0x07, 0x47,
+ 0x41, 0xef, 0xd7, 0x9c, 0x85, 0x4a, 0xe7, 0xa7,
+ 0xff, 0xf0, 0xab, 0xe5, 0x0c, 0x11, 0x08, 0x10,
+ 0x75, 0x5a, 0x68, 0xa0, 0x08, 0x03, 0xc9, 0x40,
+ 0x79, 0x67, 0x1d, 0x65, 0x89, 0x2d, 0x08, 0xf9,
+ 0xb5, 0x1b, 0x7d, 0xd2, 0x41, 0x3b, 0x33, 0xf2,
+ 0x47, 0x2f, 0x9c, 0x0b, 0xd5, 0xaf, 0xcb, 0xdb,
+ 0xbb, 0x37, 0x63, 0x03, 0xf8, 0xe7, 0x2e, 0xc7,
+ 0x3c, 0x86, 0x9f, 0xc2, 0x9b, 0xb4, 0x70, 0x6a,
+ 0x4d, 0x7c, 0xe4, 0x1b, 0x3a, 0xa9, 0xae, 0xd7,
+ 0xce, 0x7f, 0x56, 0xc2, 0x73, 0x5e, 0x58, 0x63,
+ 0xd5, 0x86, 0x41, 0x02, 0x41, 0x00, 0xf6, 0x56,
+ 0x69, 0xec, 0xef, 0x65, 0x95, 0xdc, 0x25, 0x47,
+ 0xe0, 0x6f, 0xb0, 0x4f, 0x79, 0x77, 0x0a, 0x5e,
+ 0x46, 0xcb, 0xbd, 0x0b, 0x71, 0x51, 0x2a, 0xa4,
+ 0x65, 0x29, 0x18, 0xc6, 0x30, 0xa0, 0x95, 0x4c,
+ 0x4b, 0xbe, 0x8c, 0x40, 0xe3, 0x9c, 0x23, 0x02,
+ 0x14, 0x43, 0xe9, 0x64, 0xea, 0xe3, 0xa8, 0xe2,
+ 0x1a, 0xd5, 0xf9, 0x5c, 0xe0, 0x36, 0x2c, 0x97,
+ 0xda, 0xd5, 0xc7, 0x46, 0xce, 0x11, 0x02, 0x41,
+ 0x00, 0xef, 0x56, 0x08, 0xb8, 0x29, 0xa5, 0xa6,
+ 0x7c, 0xf7, 0x5f, 0xb4, 0xf5, 0x63, 0xe7, 0xeb,
+ 0x45, 0xfd, 0x89, 0xaa, 0x94, 0xa6, 0x3d, 0x0b,
+ 0xd9, 0x04, 0x6f, 0x78, 0xe0, 0xbb, 0xa2, 0xd4,
+ 0x29, 0x83, 0x17, 0x95, 0x6f, 0x50, 0x3d, 0x40,
+ 0x5d, 0xe5, 0x24, 0xda, 0xc2, 0x23, 0x50, 0x86,
+ 0xa8, 0x34, 0xc8, 0x6f, 0xec, 0x7f, 0xb6, 0x45,
+ 0x3a, 0xdd, 0x78, 0x9b, 0xee, 0xa1, 0xe4, 0x09,
+ 0xa3, 0x02, 0x40, 0x5c, 0xd6, 0x66, 0x67, 0x58,
+ 0x35, 0xc5, 0xcb, 0xc8, 0xf5, 0x14, 0xbd, 0xa3,
+ 0x09, 0xe0, 0xb2, 0x1f, 0x63, 0x36, 0x75, 0x34,
+ 0x52, 0xea, 0xaa, 0xf7, 0x52, 0x2b, 0x99, 0xd8,
+ 0x6f, 0x61, 0x06, 0x34, 0x1e, 0x23, 0xf1, 0xb5,
+ 0x34, 0x03, 0x53, 0xe5, 0xd1, 0xb3, 0xc7, 0x80,
+ 0x5f, 0x7b, 0x32, 0xbf, 0x84, 0x2f, 0x2e, 0xf3,
+ 0x22, 0xb0, 0x91, 0x5a, 0x2f, 0x04, 0xd7, 0x4a,
+ 0x9a, 0x01, 0xb1, 0x02, 0x40, 0x34, 0x0b, 0x26,
+ 0x4c, 0x3d, 0xaa, 0x2a, 0xc0, 0xe3, 0xdd, 0xe8,
+ 0xf0, 0xaf, 0x6f, 0xe0, 0x06, 0x51, 0x32, 0x9d,
+ 0x68, 0x43, 0x99, 0xe4, 0xb8, 0xa5, 0x31, 0x44,
+ 0x3c, 0xc2, 0x30, 0x8f, 0x28, 0x13, 0xbc, 0x8e,
+ 0x1f, 0x2d, 0x78, 0x94, 0x45, 0x96, 0xad, 0x63,
+ 0xf0, 0x71, 0x53, 0x72, 0x64, 0xa3, 0x4d, 0xae,
+ 0xa0, 0xe3, 0xc8, 0x93, 0xd7, 0x50, 0x0f, 0x89,
+ 0x00, 0xe4, 0x2d, 0x3d, 0x37, 0x02, 0x41, 0x00,
+ 0xbe, 0xa6, 0x08, 0xe0, 0xc8, 0x15, 0x2a, 0x47,
+ 0xcb, 0xd5, 0xec, 0x93, 0xd3, 0xaa, 0x12, 0x82,
+ 0xaf, 0xac, 0x51, 0x5a, 0x5b, 0xa7, 0x93, 0x4b,
+ 0xb9, 0xab, 0x00, 0xfa, 0x5a, 0xea, 0x34, 0xe4,
+ 0x80, 0xf1, 0x44, 0x6a, 0x65, 0xe4, 0x33, 0x99,
+ 0xfb, 0x54, 0xd7, 0x89, 0x5a, 0x1b, 0xd6, 0x2b,
+ 0xcc, 0x6e, 0x4b, 0x19, 0xa0, 0x6d, 0x93, 0x9f,
+ 0xc3, 0x91, 0x7a, 0xa5, 0xd8, 0x59, 0x0e, 0x9e,
+};
+
+static const uint8_t rsa1024_public_key[] = {
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xe6,
+ 0x4d, 0x76, 0x4f, 0xb2, 0x97, 0x09, 0xad, 0x9d,
+ 0x17, 0x33, 0xf2, 0x30, 0x42, 0x83, 0xa9, 0xcb,
+ 0x49, 0xa4, 0x2e, 0x59, 0x5e, 0x75, 0x51, 0xd1,
+ 0xac, 0xc8, 0x86, 0x3e, 0xdb, 0x72, 0x2e, 0xb2,
+ 0xf7, 0xc3, 0x5b, 0xc7, 0xea, 0xed, 0x30, 0xd1,
+ 0xf7, 0x37, 0xee, 0x9d, 0x36, 0x59, 0x6f, 0xf8,
+ 0xce, 0xc0, 0x5c, 0x82, 0x80, 0x37, 0x83, 0xd7,
+ 0x45, 0x6a, 0xe9, 0xea, 0xc5, 0x3a, 0x59, 0x6b,
+ 0x34, 0x31, 0x44, 0x00, 0x74, 0xa7, 0x29, 0xab,
+ 0x79, 0x4a, 0xbd, 0xe8, 0x25, 0x35, 0x01, 0x11,
+ 0x40, 0xbf, 0x31, 0xbd, 0xd3, 0xe0, 0x68, 0x1e,
+ 0xd5, 0x5b, 0x2f, 0xe9, 0x20, 0xf2, 0x9f, 0x46,
+ 0x35, 0x30, 0xa8, 0xf1, 0xfe, 0xef, 0xd8, 0x76,
+ 0x23, 0x46, 0x34, 0x70, 0xa1, 0xce, 0xc6, 0x65,
+ 0x6d, 0xb0, 0x94, 0x7e, 0xe5, 0x92, 0x45, 0x7b,
+ 0xaa, 0xbb, 0x95, 0x97, 0x77, 0xcd, 0xd3, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+};
+
+static const uint8_t rsa2048_private_key[] = {
+ 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02,
+ 0x82, 0x01, 0x01, 0x00, 0xbd, 0x9c, 0x83, 0x6b,
+ 0x0e, 0x8e, 0xcf, 0xfa, 0xaa, 0x4f, 0x6a, 0xf4,
+ 0xe3, 0x52, 0x0f, 0xa5, 0xd0, 0xbe, 0x5e, 0x7f,
+ 0x08, 0x24, 0xba, 0x87, 0x46, 0xfb, 0x28, 0x93,
+ 0xe5, 0xe5, 0x81, 0x42, 0xc0, 0xf9, 0x17, 0xc7,
+ 0x81, 0x01, 0xf4, 0x18, 0x6a, 0x17, 0xf5, 0x57,
+ 0x20, 0x37, 0xcf, 0xf9, 0x74, 0x5e, 0xe1, 0x48,
+ 0x6a, 0x71, 0x0a, 0x0f, 0x79, 0x72, 0x2b, 0x46,
+ 0x10, 0x53, 0xdc, 0x14, 0x43, 0xbd, 0xbc, 0x6d,
+ 0x15, 0x6f, 0x15, 0x4e, 0xf0, 0x0d, 0x89, 0x39,
+ 0x02, 0xc3, 0x68, 0x5c, 0xa8, 0xfc, 0xed, 0x64,
+ 0x9d, 0x98, 0xb7, 0xcd, 0x83, 0x66, 0x93, 0xc3,
+ 0xd9, 0x57, 0xa0, 0x21, 0x93, 0xad, 0x5c, 0x75,
+ 0x69, 0x88, 0x9e, 0x81, 0xdc, 0x7f, 0x1d, 0xd5,
+ 0xbd, 0x1c, 0xc1, 0x30, 0x56, 0xa5, 0xda, 0x99,
+ 0x46, 0xa6, 0x6d, 0x0e, 0x6f, 0x5e, 0x51, 0x34,
+ 0x49, 0x73, 0xc3, 0x67, 0x49, 0x7e, 0x21, 0x2a,
+ 0x20, 0xa7, 0x2b, 0x92, 0x73, 0x1d, 0xa5, 0x25,
+ 0x2a, 0xd0, 0x3a, 0x89, 0x75, 0xb2, 0xbb, 0x19,
+ 0x37, 0x78, 0x48, 0xd2, 0xf2, 0x2a, 0x6d, 0x9e,
+ 0xc6, 0x26, 0xca, 0x46, 0x8c, 0xf1, 0x42, 0x2a,
+ 0x31, 0xb2, 0xfc, 0xe7, 0x55, 0x51, 0xff, 0x07,
+ 0x13, 0x5b, 0x36, 0x59, 0x2b, 0x43, 0x30, 0x4b,
+ 0x05, 0x5c, 0xd2, 0x45, 0xa0, 0xa0, 0x7c, 0x17,
+ 0x5b, 0x07, 0xbb, 0x5d, 0x83, 0x80, 0x92, 0x6d,
+ 0x87, 0x1a, 0x43, 0xac, 0xc7, 0x6b, 0x8d, 0x11,
+ 0x60, 0x27, 0xd2, 0xdf, 0xdb, 0x71, 0x02, 0x55,
+ 0x6e, 0xb5, 0xca, 0x4d, 0xda, 0x59, 0x0d, 0xb8,
+ 0x8c, 0xcd, 0xd3, 0x0e, 0x55, 0xa0, 0xa4, 0x8d,
+ 0xa0, 0x14, 0x10, 0x48, 0x42, 0x35, 0x56, 0x08,
+ 0xf7, 0x29, 0x5f, 0xa2, 0xea, 0xa4, 0x5e, 0x8e,
+ 0x99, 0x56, 0xaa, 0x5a, 0x8c, 0x23, 0x8f, 0x35,
+ 0x22, 0x8a, 0xff, 0xed, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0x02, 0x82, 0x01, 0x00, 0x4e, 0x4a, 0xf3,
+ 0x44, 0xe0, 0x64, 0xfd, 0xe1, 0xde, 0x33, 0x1e,
+ 0xd1, 0xf1, 0x8f, 0x6f, 0xe0, 0xa2, 0xfa, 0x08,
+ 0x60, 0xe1, 0xc6, 0xf0, 0xb2, 0x6d, 0x0f, 0xc6,
+ 0x28, 0x93, 0xb4, 0x19, 0x94, 0xab, 0xc3, 0xef,
+ 0x1a, 0xb4, 0xdd, 0x4e, 0xa2, 0x4a, 0x24, 0x8c,
+ 0x6c, 0xa6, 0x64, 0x05, 0x5f, 0x56, 0xba, 0xda,
+ 0xc1, 0x21, 0x1a, 0x7d, 0xf1, 0xf7, 0xce, 0xb9,
+ 0xa9, 0x9b, 0x92, 0x54, 0xfc, 0x95, 0x20, 0x22,
+ 0x4e, 0xd4, 0x9b, 0xe2, 0xab, 0x8e, 0x99, 0xb8,
+ 0x40, 0xaf, 0x30, 0x6a, 0xc6, 0x60, 0x0c, 0xd8,
+ 0x25, 0x44, 0xa1, 0xcb, 0xbb, 0x73, 0x77, 0x86,
+ 0xaa, 0x46, 0xf3, 0x54, 0xae, 0xa8, 0xa0, 0xdb,
+ 0xdd, 0xab, 0x6e, 0xfb, 0x2c, 0x5a, 0x14, 0xaf,
+ 0x08, 0x13, 0xa7, 0x6c, 0xe9, 0xfd, 0xcd, 0x4c,
+ 0x1f, 0x20, 0x3a, 0x16, 0x2b, 0xf0, 0xb6, 0x7c,
+ 0x47, 0x5f, 0xd1, 0x0a, 0x2c, 0xc4, 0xa5, 0x68,
+ 0xd0, 0x43, 0x75, 0x6b, 0x65, 0xaa, 0x32, 0xc6,
+ 0x99, 0x06, 0xcb, 0x8f, 0xe6, 0x8d, 0xce, 0xbf,
+ 0x4d, 0x0d, 0x7b, 0x22, 0x2a, 0x8a, 0xcb, 0x7d,
+ 0x7f, 0x16, 0x48, 0x85, 0xf1, 0x86, 0xcb, 0x54,
+ 0xb9, 0x39, 0xd4, 0xbc, 0xe3, 0x2d, 0x27, 0x59,
+ 0xf6, 0x81, 0x5e, 0x94, 0x45, 0xdf, 0xb9, 0x22,
+ 0xaf, 0x64, 0x0d, 0x14, 0xec, 0x8c, 0xeb, 0x71,
+ 0xac, 0xee, 0x09, 0x4c, 0xbf, 0x34, 0xf9, 0xf4,
+ 0x66, 0x77, 0x36, 0x3b, 0x41, 0x74, 0x01, 0x4f,
+ 0xfc, 0x56, 0x83, 0xba, 0x14, 0xb0, 0x2f, 0xdd,
+ 0x4d, 0xb9, 0x3f, 0xdf, 0x71, 0xbe, 0x7b, 0xba,
+ 0x66, 0xc8, 0xc5, 0x42, 0xc9, 0xba, 0x18, 0x63,
+ 0x45, 0x07, 0x2f, 0x84, 0x3e, 0xc3, 0xfb, 0x47,
+ 0xda, 0xd4, 0x1d, 0x0e, 0x9d, 0x96, 0xc0, 0xea,
+ 0xee, 0x45, 0x2f, 0xe1, 0x62, 0x23, 0xee, 0xef,
+ 0x3d, 0x5e, 0x55, 0xa1, 0x0d, 0x02, 0x81, 0x81,
+ 0x00, 0xeb, 0x76, 0x88, 0xd3, 0xae, 0x3f, 0x1d,
+ 0xf2, 0x49, 0xe0, 0x37, 0x49, 0x83, 0x82, 0x6c,
+ 0xf7, 0xf1, 0x17, 0x30, 0x75, 0x2e, 0x89, 0x06,
+ 0x88, 0x56, 0x32, 0xf6, 0xfa, 0x58, 0xcb, 0x3c,
+ 0x98, 0x67, 0xc3, 0xde, 0x10, 0x82, 0xe5, 0xfa,
+ 0xfa, 0x52, 0x47, 0x8d, 0xd7, 0x00, 0xc6, 0xcb,
+ 0xf7, 0xf6, 0x57, 0x9b, 0x6e, 0x0c, 0xac, 0xe8,
+ 0x3b, 0xd1, 0xde, 0xb5, 0x34, 0xaf, 0x8b, 0x2a,
+ 0xb0, 0x2d, 0x01, 0xeb, 0x7c, 0xa0, 0x42, 0x26,
+ 0xbb, 0x2b, 0x43, 0x0e, 0x1d, 0xe2, 0x4e, 0xc9,
+ 0xc1, 0x0a, 0x67, 0x1d, 0xfc, 0x83, 0x25, 0xce,
+ 0xb2, 0x18, 0xd9, 0x0d, 0x70, 0xf5, 0xa3, 0x5a,
+ 0x9c, 0x99, 0xdd, 0x47, 0xa1, 0x57, 0xe7, 0x20,
+ 0xde, 0xa1, 0x29, 0x8d, 0x96, 0x62, 0xf9, 0x26,
+ 0x95, 0x51, 0xa6, 0xe7, 0x09, 0x8b, 0xba, 0x16,
+ 0x8b, 0x19, 0x5b, 0xf9, 0x27, 0x0d, 0xc5, 0xd6,
+ 0x5f, 0x02, 0x81, 0x81, 0x00, 0xce, 0x26, 0x31,
+ 0xb5, 0x43, 0x53, 0x95, 0x39, 0xdd, 0x01, 0x98,
+ 0x8b, 0x3d, 0x27, 0xeb, 0x0b, 0x87, 0x1c, 0x95,
+ 0xfc, 0x3e, 0x36, 0x51, 0x31, 0xb5, 0xea, 0x59,
+ 0x56, 0xc0, 0x97, 0x62, 0xf0, 0x63, 0x2b, 0xb6,
+ 0x30, 0x9b, 0xdf, 0x19, 0x10, 0xe9, 0xa0, 0x3d,
+ 0xea, 0x54, 0x5a, 0xe6, 0xc6, 0x9e, 0x7e, 0xb5,
+ 0xf0, 0xb0, 0x54, 0xef, 0xc3, 0xe1, 0x47, 0xa6,
+ 0x95, 0xc7, 0xe4, 0xa3, 0x4a, 0x30, 0x68, 0x24,
+ 0x98, 0x7d, 0xc1, 0x34, 0xa9, 0xcb, 0xbc, 0x3c,
+ 0x08, 0x9c, 0x7d, 0x0c, 0xa2, 0xb7, 0x60, 0xaa,
+ 0x38, 0x08, 0x16, 0xa6, 0x7f, 0xdb, 0xd2, 0xb1,
+ 0x67, 0xe7, 0x93, 0x8e, 0xbb, 0x7e, 0xb9, 0xb5,
+ 0xd0, 0xd0, 0x9f, 0x7b, 0xcc, 0x46, 0xe6, 0x74,
+ 0x78, 0x1a, 0x96, 0xd6, 0xd7, 0x74, 0x34, 0x54,
+ 0x3b, 0x54, 0x55, 0x7f, 0x89, 0x81, 0xbc, 0x40,
+ 0x55, 0x87, 0x24, 0x95, 0x33, 0x02, 0x81, 0x81,
+ 0x00, 0xb0, 0x18, 0x5d, 0x2a, 0x1a, 0x95, 0x9f,
+ 0x9a, 0xd5, 0x3f, 0x37, 0x79, 0xe6, 0x3d, 0x83,
+ 0xab, 0x46, 0x86, 0x36, 0x3a, 0x5d, 0x0c, 0x23,
+ 0x73, 0x91, 0x2b, 0xda, 0x63, 0xce, 0x46, 0x68,
+ 0xd1, 0xfe, 0x40, 0x90, 0xf2, 0x3e, 0x43, 0x2b,
+ 0x19, 0x4c, 0xb1, 0xb0, 0xd5, 0x8c, 0x02, 0x21,
+ 0x07, 0x18, 0x17, 0xda, 0xe9, 0x49, 0xd7, 0x82,
+ 0x73, 0x42, 0x78, 0xd1, 0x82, 0x4e, 0x8a, 0xc0,
+ 0xe9, 0x33, 0x2f, 0xcd, 0x62, 0xce, 0x23, 0xca,
+ 0xfd, 0x8d, 0xd4, 0x3f, 0x59, 0x80, 0x27, 0xb6,
+ 0x61, 0x85, 0x9b, 0x2a, 0xe4, 0xef, 0x5c, 0x36,
+ 0x22, 0x21, 0xcd, 0x2a, 0x6d, 0x41, 0x77, 0xe2,
+ 0xcb, 0x5d, 0x93, 0x0d, 0x00, 0x10, 0x52, 0x8d,
+ 0xd5, 0x92, 0x28, 0x16, 0x78, 0xd3, 0x1a, 0x4c,
+ 0x8d, 0xbd, 0x9c, 0x1a, 0x0b, 0x9c, 0x91, 0x16,
+ 0x4c, 0xff, 0x31, 0x36, 0xbb, 0xcb, 0x64, 0x1a,
+ 0xf7, 0x02, 0x81, 0x80, 0x32, 0x65, 0x09, 0xdf,
+ 0xca, 0xee, 0xa2, 0xdb, 0x3b, 0x58, 0xc9, 0x86,
+ 0xb8, 0x53, 0x8a, 0xd5, 0x0d, 0x99, 0x82, 0x5c,
+ 0xe0, 0x84, 0x7c, 0xc2, 0xcf, 0x3a, 0xd3, 0xce,
+ 0x2e, 0x54, 0x93, 0xbe, 0x3a, 0x30, 0x14, 0x60,
+ 0xbb, 0xaa, 0x05, 0x41, 0xaa, 0x2b, 0x1f, 0x17,
+ 0xaa, 0xb9, 0x72, 0x12, 0xf9, 0xe9, 0xf5, 0xe6,
+ 0x39, 0xe4, 0xf9, 0x9c, 0x03, 0xf5, 0x75, 0x16,
+ 0xc6, 0x7f, 0xf1, 0x1f, 0x10, 0xc8, 0x54, 0xb1,
+ 0xe6, 0x84, 0x15, 0xb0, 0xb0, 0x7a, 0x7a, 0x9e,
+ 0x8c, 0x4a, 0xd1, 0x8c, 0xf1, 0x91, 0x32, 0xeb,
+ 0x71, 0xa6, 0xbf, 0xdb, 0x1f, 0xcc, 0xd8, 0xcb,
+ 0x92, 0xc3, 0xf2, 0xaf, 0x89, 0x22, 0x32, 0xfd,
+ 0x32, 0x12, 0xda, 0xbb, 0xac, 0x55, 0x68, 0x01,
+ 0x78, 0x56, 0x89, 0x7c, 0xb0, 0x0e, 0x9e, 0xcc,
+ 0xc6, 0x28, 0x04, 0x7e, 0x83, 0xf5, 0x96, 0x30,
+ 0x92, 0x51, 0xf2, 0x1b, 0x02, 0x81, 0x81, 0x00,
+ 0x83, 0x6d, 0xd1, 0x98, 0x90, 0x41, 0x8c, 0xa7,
+ 0x92, 0x83, 0xac, 0x89, 0x05, 0x0c, 0x79, 0x67,
+ 0x90, 0xb6, 0xa1, 0xf3, 0x2f, 0xca, 0xf0, 0x15,
+ 0xe0, 0x30, 0x58, 0xe9, 0x4f, 0xcb, 0x4c, 0x56,
+ 0x56, 0x56, 0x14, 0x3f, 0x1b, 0x79, 0xb6, 0xef,
+ 0x57, 0x4b, 0x28, 0xbd, 0xb0, 0xe6, 0x0c, 0x49,
+ 0x4b, 0xbe, 0xe1, 0x57, 0x28, 0x2a, 0x23, 0x5e,
+ 0xc4, 0xa2, 0x19, 0x4b, 0x00, 0x67, 0x78, 0xd9,
+ 0x26, 0x6e, 0x17, 0x25, 0xce, 0xe4, 0xfd, 0xde,
+ 0x86, 0xa8, 0x5a, 0x67, 0x47, 0x6b, 0x15, 0x09,
+ 0xe1, 0xec, 0x8e, 0x62, 0x98, 0x91, 0x6f, 0xc0,
+ 0x98, 0x0c, 0x70, 0x0e, 0x7d, 0xbe, 0x63, 0xbd,
+ 0x12, 0x5a, 0x98, 0x1c, 0xe3, 0x0c, 0xfb, 0xc7,
+ 0xfb, 0x1b, 0xbd, 0x02, 0x87, 0xcc, 0x0c, 0xbb,
+ 0xc2, 0xd4, 0xb6, 0xc1, 0xa1, 0x23, 0xd3, 0x1e,
+ 0x21, 0x6f, 0x48, 0xba, 0x0e, 0x2e, 0xc7, 0x42
+};
+
+static const uint8_t rsa2048_public_key[] = {
+ 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+ 0x00, 0xbd, 0x9c, 0x83, 0x6b, 0x0e, 0x8e, 0xcf,
+ 0xfa, 0xaa, 0x4f, 0x6a, 0xf4, 0xe3, 0x52, 0x0f,
+ 0xa5, 0xd0, 0xbe, 0x5e, 0x7f, 0x08, 0x24, 0xba,
+ 0x87, 0x46, 0xfb, 0x28, 0x93, 0xe5, 0xe5, 0x81,
+ 0x42, 0xc0, 0xf9, 0x17, 0xc7, 0x81, 0x01, 0xf4,
+ 0x18, 0x6a, 0x17, 0xf5, 0x57, 0x20, 0x37, 0xcf,
+ 0xf9, 0x74, 0x5e, 0xe1, 0x48, 0x6a, 0x71, 0x0a,
+ 0x0f, 0x79, 0x72, 0x2b, 0x46, 0x10, 0x53, 0xdc,
+ 0x14, 0x43, 0xbd, 0xbc, 0x6d, 0x15, 0x6f, 0x15,
+ 0x4e, 0xf0, 0x0d, 0x89, 0x39, 0x02, 0xc3, 0x68,
+ 0x5c, 0xa8, 0xfc, 0xed, 0x64, 0x9d, 0x98, 0xb7,
+ 0xcd, 0x83, 0x66, 0x93, 0xc3, 0xd9, 0x57, 0xa0,
+ 0x21, 0x93, 0xad, 0x5c, 0x75, 0x69, 0x88, 0x9e,
+ 0x81, 0xdc, 0x7f, 0x1d, 0xd5, 0xbd, 0x1c, 0xc1,
+ 0x30, 0x56, 0xa5, 0xda, 0x99, 0x46, 0xa6, 0x6d,
+ 0x0e, 0x6f, 0x5e, 0x51, 0x34, 0x49, 0x73, 0xc3,
+ 0x67, 0x49, 0x7e, 0x21, 0x2a, 0x20, 0xa7, 0x2b,
+ 0x92, 0x73, 0x1d, 0xa5, 0x25, 0x2a, 0xd0, 0x3a,
+ 0x89, 0x75, 0xb2, 0xbb, 0x19, 0x37, 0x78, 0x48,
+ 0xd2, 0xf2, 0x2a, 0x6d, 0x9e, 0xc6, 0x26, 0xca,
+ 0x46, 0x8c, 0xf1, 0x42, 0x2a, 0x31, 0xb2, 0xfc,
+ 0xe7, 0x55, 0x51, 0xff, 0x07, 0x13, 0x5b, 0x36,
+ 0x59, 0x2b, 0x43, 0x30, 0x4b, 0x05, 0x5c, 0xd2,
+ 0x45, 0xa0, 0xa0, 0x7c, 0x17, 0x5b, 0x07, 0xbb,
+ 0x5d, 0x83, 0x80, 0x92, 0x6d, 0x87, 0x1a, 0x43,
+ 0xac, 0xc7, 0x6b, 0x8d, 0x11, 0x60, 0x27, 0xd2,
+ 0xdf, 0xdb, 0x71, 0x02, 0x55, 0x6e, 0xb5, 0xca,
+ 0x4d, 0xda, 0x59, 0x0d, 0xb8, 0x8c, 0xcd, 0xd3,
+ 0x0e, 0x55, 0xa0, 0xa4, 0x8d, 0xa0, 0x14, 0x10,
+ 0x48, 0x42, 0x35, 0x56, 0x08, 0xf7, 0x29, 0x5f,
+ 0xa2, 0xea, 0xa4, 0x5e, 0x8e, 0x99, 0x56, 0xaa,
+ 0x5a, 0x8c, 0x23, 0x8f, 0x35, 0x22, 0x8a, 0xff,
+ 0xed, 0x02, 0x03, 0x01, 0x00, 0x01
+};
+
+static const uint8_t test_sha1_dgst[] = {
+ 0x3c, 0x05, 0x19, 0x34, 0x29, 0x19, 0xc7, 0xe0,
+ 0x87, 0xb6, 0x24, 0xf9, 0x58, 0xac, 0xa4, 0xd4,
+ 0xb2, 0xd9, 0x03, 0x9e,
+};
+
+static const uint8_t exp_signature_rsa2048_pkcs1[] = {
+ 0x4e, 0x82, 0x56, 0x4c, 0x84, 0x66, 0xca, 0x1e,
+ 0xc6, 0x92, 0x46, 0x20, 0x02, 0x6b, 0x64, 0x46,
+ 0x15, 0x6b, 0x24, 0xf2, 0xbb, 0xfa, 0x44, 0x3c,
+ 0xaf, 0x42, 0xc8, 0x41, 0xfd, 0xce, 0xed, 0x95,
+ 0x34, 0xaf, 0x25, 0x09, 0xd1, 0x06, 0x94, 0xaa,
+ 0x52, 0xd4, 0x29, 0xc8, 0x52, 0x34, 0x67, 0x59,
+ 0x4f, 0x5a, 0xfd, 0x23, 0x30, 0x5e, 0xc7, 0x1e,
+ 0xa6, 0xe0, 0x1b, 0x23, 0xca, 0x82, 0x47, 0x9a,
+ 0x2e, 0x2c, 0x66, 0x45, 0x5a, 0x12, 0xa9, 0x15,
+ 0xbf, 0xd6, 0xd6, 0xfa, 0x8d, 0x60, 0x99, 0x89,
+ 0x91, 0x39, 0x06, 0xb7, 0xd3, 0x9a, 0xef, 0x15,
+ 0x7b, 0x95, 0x87, 0x77, 0x2c, 0x41, 0xd4, 0x71,
+ 0xd5, 0xdf, 0x22, 0x7b, 0x01, 0xe2, 0xc1, 0xfb,
+ 0xb9, 0x4e, 0x0c, 0x9b, 0xd5, 0x04, 0xed, 0x2b,
+ 0x7e, 0x73, 0x53, 0xaa, 0x33, 0x89, 0x9d, 0x95,
+ 0x28, 0x8f, 0x8b, 0x80, 0x34, 0x7a, 0xea, 0xe3,
+ 0x66, 0x8a, 0xa8, 0xad, 0xed, 0x91, 0x43, 0xdd,
+ 0x77, 0xe5, 0xd7, 0x16, 0xda, 0xa8, 0x00, 0x29,
+ 0x3f, 0x9f, 0xe0, 0x1d, 0x42, 0x9d, 0x35, 0x5d,
+ 0x0f, 0xf3, 0x90, 0x27, 0x3a, 0x8c, 0x46, 0x13,
+ 0x53, 0x3e, 0x3b, 0x38, 0x77, 0xf8, 0x57, 0x61,
+ 0xbc, 0xc4, 0x54, 0x68, 0x48, 0xae, 0x58, 0x03,
+ 0x33, 0x94, 0x3f, 0x18, 0x1e, 0xb3, 0x3f, 0x79,
+ 0xa7, 0x26, 0x92, 0x5d, 0x32, 0x2a, 0xdb, 0xe6,
+ 0x3a, 0xe8, 0xd7, 0xaa, 0x91, 0xfe, 0x9f, 0x06,
+ 0x26, 0x68, 0x8c, 0x27, 0x31, 0xb0, 0x04, 0x9e,
+ 0x94, 0x79, 0x63, 0xa1, 0xc7, 0xe8, 0x5b, 0x8c,
+ 0xd3, 0xf1, 0x88, 0x58, 0x31, 0x2f, 0x4e, 0x11,
+ 0x00, 0xfe, 0x29, 0xad, 0x2c, 0xa9, 0x8e, 0x63,
+ 0xd8, 0x7d, 0xc5, 0xa1, 0x71, 0xfa, 0x08, 0x29,
+ 0xea, 0xd6, 0x6c, 0x53, 0x00, 0x52, 0xa0, 0xed,
+ 0x6b, 0x7c, 0x67, 0x50, 0x71, 0x2d, 0x96, 0x7a,
+};
+
+static const uint8_t exp_signature_rsa1024_pkcs1[] = {
+ 0x6b, 0x5b, 0xbb, 0x3b, 0x1f, 0x08, 0xd8, 0xc0,
+ 0x4a, 0xf1, 0x5a, 0x12, 0xc2, 0x39, 0x14, 0x65,
+ 0x4f, 0xda, 0x79, 0x67, 0xf2, 0x89, 0x25, 0xad,
+ 0x9e, 0x7e, 0xba, 0xa8, 0x34, 0x15, 0x03, 0xdd,
+ 0x80, 0x6b, 0x01, 0xd7, 0x4a, 0xf3, 0xd6, 0xef,
+ 0x1e, 0x48, 0xf3, 0xbc, 0x75, 0x1a, 0xc4, 0x2c,
+ 0x90, 0x15, 0x9f, 0x21, 0x24, 0x98, 0x21, 0xef,
+ 0x6d, 0x3b, 0xf3, 0x82, 0x8f, 0x8d, 0xd8, 0x48,
+ 0x37, 0x16, 0x19, 0x8e, 0x3c, 0x64, 0xa0, 0x9e,
+ 0xf7, 0x0c, 0xd9, 0x5c, 0xc6, 0x13, 0xc4, 0x5f,
+ 0xf8, 0xf3, 0x59, 0x5b, 0xd0, 0x33, 0x95, 0x98,
+ 0xde, 0x67, 0x25, 0x58, 0x46, 0xba, 0xee, 0x0f,
+ 0x47, 0x7a, 0x7f, 0xd0, 0xe4, 0x77, 0x09, 0x17,
+ 0xe9, 0x81, 0x6e, 0x2d, 0x33, 0x9b, 0x13, 0x0b,
+ 0xc9, 0xb2, 0x0c, 0x2c, 0xb5, 0xdf, 0x52, 0x8f,
+ 0xab, 0x0d, 0xc6, 0x59, 0x1d, 0xc7, 0x33, 0x7b,
+};
+
+static const uint8_t test_plaintext[] = {
+ 0x00, 0x44, 0xbc, 0x6f, 0x77, 0xfb, 0xe2, 0xa4,
+ 0x98, 0x9e, 0xf5, 0x33, 0xa0, 0xbd, 0x81, 0xb9,
+ 0xf1, 0x44, 0x7f, 0x79, 0x89, 0x23, 0xe5, 0x46,
+ 0x66, 0x9f, 0x98, 0x95, 0x6f, 0x56, 0x78, 0xf6,
+ 0xf5, 0xac, 0x9c, 0xda, 0xc2, 0x79, 0x59, 0xf0,
+ 0x1b, 0x03, 0xfa, 0x46, 0x1c, 0x1f, 0x18, 0x07,
+ 0xce, 0xad, 0xed, 0x3d, 0x11, 0xf9, 0x1b, 0x26,
+ 0x4a, 0x97, 0x28, 0x71, 0x5f, 0x2c, 0x5e, 0x58,
+ 0xf0, 0xd6, 0xbf, 0xa4, 0x12, 0xd0, 0x1d, 0x07,
+ 0xcb, 0x73, 0x66, 0xb6, 0xa4, 0x09, 0xaf, 0x5d,
+ 0xe9, 0x14, 0x14, 0xaf, 0x69, 0xd6, 0xee, 0x0a,
+ 0xfc, 0xca, 0xac, 0x94, 0x47, 0xd5, 0x9d, 0x5b,
+ 0x2b, 0xfb, 0xce, 0x9d, 0x04, 0xc1, 0xaf, 0xa5,
+ 0xa1, 0x8d, 0xa9, 0x48, 0xa8, 0x65, 0xe6, 0x9f,
+ 0x74, 0x78, 0x16, 0x32, 0x93, 0xb5, 0x21, 0xb9,
+ 0x9f, 0x3f, 0xc1, 0xe5, 0xa2, 0x50, 0x8b, 0x12,
+ 0xfb, 0x3e, 0xb0, 0x8a, 0x00, 0xc7, 0x20, 0x56,
+ 0xb3, 0xb1, 0x29, 0x95, 0x89, 0xd6, 0x50, 0xf5,
+ 0x37, 0x38, 0x8e, 0x12, 0xf1, 0xba, 0x82, 0x37,
+ 0x34, 0x68, 0x4b, 0xe8, 0xe3, 0x11, 0x1c, 0x46,
+ 0xf9, 0x63, 0x3a, 0xd6, 0xf3, 0x3f, 0x55, 0xa6,
+ 0xbd, 0x89, 0xf1, 0x2d, 0x38, 0x91, 0x7c, 0xc2,
+ 0x4d, 0xf1, 0x69, 0x82, 0x6d, 0x71, 0x77, 0xf4,
+ 0xfc, 0x43, 0x20, 0x6f, 0x43, 0xb9, 0x43, 0xd1,
+ 0x65, 0xbd, 0xca, 0xb1, 0x43, 0x87, 0xf8, 0xc8,
+ 0x76, 0x21, 0xa9, 0xeb, 0x3e, 0x9a, 0xef, 0xc9,
+ 0x0e, 0x79, 0xbc, 0xf0, 0xf8, 0xc8, 0xe2, 0xbc,
+ 0x33, 0x35, 0x3e, 0xfc, 0xf9, 0x44, 0x69, 0x06,
+ 0x7c, 0x7f, 0x5d, 0xa2, 0x9e, 0xab, 0xc2, 0x82,
+ 0xa0, 0xfb, 0xc5, 0x79, 0x57, 0x8c, 0xf1, 0x1c,
+ 0x51, 0x64, 0x4c, 0x56, 0x08, 0x80, 0x32, 0xf4,
+ 0x97, 0x8f, 0x6f, 0xb2, 0x16, 0xa6, 0x9d, 0x71,
+};
+
+static const uint8_t exp_ciphertext_rsa1024_raw[] = {
+ 0x01, 0xa0, 0xc2, 0x94, 0x9f, 0xd6, 0xbe, 0x8d,
+ 0xe9, 0x24, 0xaa, 0x9c, 0x67, 0xd7, 0xe3, 0x04,
+ 0x34, 0xbf, 0xd3, 0x27, 0xa1, 0x43, 0xeb, 0x60,
+ 0x6b, 0x5b, 0x64, 0x15, 0x55, 0x16, 0x98, 0x35,
+ 0xc2, 0x59, 0xa7, 0xf7, 0x24, 0xf7, 0x05, 0xb9,
+ 0xe8, 0x56, 0x6f, 0xf2, 0x7d, 0x8b, 0x3c, 0xcb,
+ 0xa6, 0xc2, 0xac, 0x0c, 0x37, 0x8c, 0x70, 0x70,
+ 0x55, 0x05, 0x07, 0x0d, 0x63, 0x6b, 0x7d, 0x5f,
+ 0xae, 0x03, 0x1e, 0x55, 0x05, 0xbb, 0xa8, 0xe7,
+ 0xff, 0xa0, 0x8c, 0x5b, 0x6b, 0x01, 0x48, 0x2e,
+ 0x4f, 0x7f, 0xe2, 0x74, 0xc6, 0x32, 0xa7, 0x2d,
+ 0xdb, 0x91, 0x9b, 0x67, 0x4d, 0x71, 0xf9, 0x8c,
+ 0x42, 0x43, 0x75, 0x4e, 0xd0, 0x0e, 0x7c, 0xa0,
+ 0x97, 0x1a, 0x5f, 0x8e, 0x6f, 0xe4, 0xfa, 0x16,
+ 0x1d, 0x59, 0x0e, 0x0b, 0x11, 0x12, 0xa3, 0x0c,
+ 0xa6, 0x55, 0xe6, 0xdb, 0xa7, 0x71, 0xa6, 0xff,
+};
+
+static const uint8_t exp_ciphertext_rsa1024_pkcs1[] = {
+ 0x93, 0x78, 0x6a, 0x76, 0xb8, 0x94, 0xea, 0xe4,
+ 0x32, 0x79, 0x01, 0x8b, 0xc1, 0xcb, 0x2e, 0x2d,
+ 0xfe, 0xdc, 0x9b, 0xe3, 0xe9, 0x23, 0xe4, 0x0a,
+ 0xb0, 0x6b, 0x9f, 0x6b, 0x62, 0xf5, 0x3d, 0xf0,
+ 0x78, 0x84, 0x77, 0x21, 0xad, 0x0b, 0x30, 0x30,
+ 0x94, 0xe2, 0x18, 0xc4, 0x9b, 0x12, 0x06, 0xc8,
+ 0xaa, 0xf7, 0x30, 0xe4, 0xc8, 0x64, 0xe7, 0x51,
+ 0xf1, 0x6a, 0xe1, 0xa2, 0x58, 0x7a, 0x02, 0x9c,
+ 0x8e, 0xf0, 0x2d, 0x25, 0x6b, 0xb7, 0x25, 0x5e,
+ 0x05, 0xaf, 0x38, 0xb2, 0x69, 0x5e, 0x6c, 0x75,
+ 0x6e, 0x27, 0xba, 0x5d, 0x7d, 0x35, 0x72, 0xb7,
+ 0x25, 0xd4, 0xaa, 0xb2, 0x4b, 0x9e, 0x6b, 0x82,
+ 0xb2, 0x32, 0xe2, 0x13, 0x1d, 0x00, 0x21, 0x08,
+ 0xae, 0x14, 0xbb, 0xc0, 0x40, 0xb7, 0x0d, 0xd5,
+ 0x0e, 0x4d, 0x6d, 0x9a, 0x70, 0x86, 0xe9, 0xfc,
+ 0x67, 0x2b, 0xa4, 0x11, 0x45, 0xb6, 0xc4, 0x2f,
+};
+
+static const uint8_t exp_ciphertext_rsa2048_raw[] = {
+ 0x09, 0x7b, 0x9e, 0x7c, 0x10, 0x1f, 0x73, 0xb4,
+ 0x5f, 0xdb, 0x4f, 0x05, 0xe7, 0xfc, 0x9e, 0x35,
+ 0x48, 0xd8, 0xc8, 0xf5, 0xac, 0x6d, 0xb4, 0xb0,
+ 0xd4, 0xf7, 0x69, 0x0f, 0x30, 0x78, 0xbb, 0x55,
+ 0x67, 0x66, 0x66, 0x05, 0xf4, 0x77, 0xe2, 0x30,
+ 0xa5, 0x94, 0x10, 0xa3, 0xcb, 0xee, 0x13, 0x9f,
+ 0x47, 0x1b, 0x2e, 0xf9, 0xfd, 0x94, 0x09, 0xbd,
+ 0x26, 0x6e, 0x84, 0xc7, 0x5c, 0x42, 0x20, 0x76,
+ 0x72, 0x83, 0x75, 0x68, 0xa4, 0x18, 0x2d, 0x76,
+ 0x62, 0xc3, 0xab, 0xc0, 0xc9, 0x36, 0x59, 0xe0,
+ 0xa9, 0x70, 0x1f, 0xff, 0x97, 0x07, 0x0d, 0x88,
+ 0xc2, 0xd8, 0x51, 0x35, 0xf7, 0xb0, 0x50, 0xe4,
+ 0x9f, 0x3d, 0xd4, 0x71, 0x8b, 0x40, 0x89, 0x71,
+ 0x6c, 0xd8, 0xc2, 0x63, 0xb6, 0x3a, 0xce, 0xb1,
+ 0x32, 0xf1, 0xc6, 0x11, 0x31, 0x25, 0x48, 0xcf,
+ 0xeb, 0xbc, 0xd3, 0x9b, 0xc5, 0xbd, 0xd2, 0x57,
+ 0x73, 0x9b, 0x20, 0xb8, 0xdf, 0xbe, 0xb8, 0x40,
+ 0xb6, 0xac, 0x24, 0xdb, 0x94, 0x6a, 0x93, 0x43,
+ 0x4a, 0xa8, 0xa3, 0xcf, 0xd5, 0x61, 0x1b, 0x46,
+ 0x1d, 0x6f, 0x57, 0xec, 0xa6, 0xd0, 0x44, 0x05,
+ 0x48, 0xb8, 0x90, 0x80, 0x23, 0x8e, 0x5f, 0xb0,
+ 0x4b, 0x6f, 0xe3, 0xf9, 0xb0, 0x04, 0x60, 0xae,
+ 0x80, 0xcf, 0xa5, 0x5c, 0x11, 0xe4, 0xce, 0x57,
+ 0x5b, 0xbb, 0xde, 0x92, 0xfc, 0xe7, 0x3f, 0xe0,
+ 0xfc, 0x06, 0xc8, 0xf3, 0x8c, 0xac, 0x86, 0x09,
+ 0x31, 0xe5, 0x7e, 0xfb, 0x5d, 0xa7, 0x57, 0xf8,
+ 0x1d, 0x23, 0x9d, 0xa3, 0xeb, 0x53, 0x28, 0xde,
+ 0xbf, 0x53, 0xef, 0x35, 0x3c, 0x7e, 0x3c, 0x1b,
+ 0x76, 0x9d, 0x09, 0x25, 0x43, 0xd4, 0x8b, 0xca,
+ 0xda, 0x45, 0x5b, 0xdc, 0x9f, 0x57, 0x5a, 0x30,
+ 0x2e, 0xe9, 0x73, 0x68, 0x28, 0xfa, 0x40, 0xb0,
+ 0x7c, 0x31, 0xd7, 0x8b, 0x4e, 0x99, 0x94, 0xf1,
+};
+
+static const uint8_t exp_ciphertext_rsa2048_pkcs1[] = {
+ 0xa5, 0x19, 0x19, 0x34, 0xad, 0xf6, 0xd2, 0xbe,
+ 0xed, 0x8f, 0xe5, 0xfe, 0xa2, 0xa5, 0x20, 0x08,
+ 0x15, 0x53, 0x7c, 0x68, 0x28, 0xae, 0x07, 0xb2,
+ 0x4c, 0x5d, 0xee, 0xc1, 0xc6, 0xdc, 0xd6, 0x8b,
+ 0xc6, 0xba, 0x46, 0xe1, 0x16, 0xa9, 0x04, 0x72,
+ 0xdf, 0x8f, 0x1e, 0x97, 0x2a, 0x55, 0xe7, 0xac,
+ 0x08, 0x0d, 0x61, 0xe8, 0x64, 0x8b, 0x6f, 0x96,
+ 0x0e, 0xbb, 0x8a, 0x30, 0xb3, 0x73, 0x28, 0x61,
+ 0x16, 0x89, 0x90, 0x88, 0x8e, 0xda, 0x22, 0xe6,
+ 0x42, 0x16, 0xc7, 0xe8, 0x30, 0x0d, 0x7f, 0x44,
+ 0x1e, 0xef, 0xe6, 0xdb, 0x78, 0x54, 0x89, 0xa5,
+ 0x60, 0x67, 0xb3, 0x35, 0x2d, 0x79, 0x49, 0xcf,
+ 0xe6, 0x8f, 0xf3, 0x64, 0x52, 0x1c, 0x6c, 0x43,
+ 0x7e, 0xb0, 0xde, 0x55, 0xdf, 0xbe, 0xb7, 0xb1,
+ 0xdb, 0x02, 0xee, 0x76, 0x96, 0xcc, 0x0b, 0x97,
+ 0x8c, 0x23, 0xaa, 0x7d, 0x4c, 0x47, 0x28, 0x41,
+ 0x7a, 0x20, 0x39, 0x1f, 0x64, 0x0b, 0xf1, 0x74,
+ 0xf1, 0x29, 0xda, 0xe9, 0x3a, 0x36, 0xa6, 0x88,
+ 0xb8, 0xc0, 0x21, 0xb8, 0x9b, 0x5d, 0x90, 0x85,
+ 0xa3, 0x30, 0x61, 0x17, 0x8c, 0x74, 0x63, 0xd5,
+ 0x0f, 0x95, 0xdc, 0xc8, 0x4f, 0xa7, 0x24, 0x55,
+ 0x40, 0xe2, 0x84, 0x57, 0x65, 0x06, 0x11, 0x30,
+ 0x2b, 0x9e, 0x32, 0x95, 0x39, 0xf2, 0x1a, 0x3f,
+ 0xab, 0xcd, 0x7b, 0x7f, 0x9c, 0xf0, 0x00, 0x50,
+ 0x7c, 0xf4, 0xbe, 0xcb, 0x80, 0xea, 0x66, 0xba,
+ 0x0e, 0x7b, 0x46, 0x0b, 0x25, 0xe0, 0xc1, 0x03,
+ 0x29, 0x11, 0x2d, 0x69, 0x4f, 0x21, 0xa2, 0x58,
+ 0x37, 0x4b, 0x84, 0x15, 0xb3, 0x65, 0x3a, 0xac,
+ 0xd4, 0xd0, 0xf6, 0xdf, 0x4b, 0x82, 0xca, 0x9e,
+ 0xbb, 0xbe, 0x3c, 0x4d, 0xd5, 0xbf, 0x00, 0xd6,
+ 0x12, 0x48, 0x72, 0x0b, 0xc7, 0xf8, 0xe1, 0xcd,
+ 0xd0, 0x28, 0x03, 0x19, 0xa6, 0x06, 0x13, 0x45,
+};
+
+typedef struct QCryptoAkCipherTestData QCryptoAkCipherTestData;
+struct QCryptoAkCipherTestData {
+ const char *path;
+ QCryptoAkCipherOptions opt;
+
+ const uint8_t *priv_key;
+ size_t priv_key_len;
+ const uint8_t *pub_key;
+ size_t pub_key_len;
+
+ const uint8_t *plaintext;
+ size_t plen;
+ const uint8_t *ciphertext;
+ size_t clen;
+ const uint8_t *dgst;
+ size_t dlen;
+ const uint8_t *signature;
+ size_t slen;
+};
+
+static QCryptoAkCipherTestData test_data[] = {
+ /* rsa1024 with raw padding */
+ {
+ .path = "/crypto/akcipher/rsa1024-raw",
+ .opt = {
+ .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .u.rsa = {
+ .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW,
+ },
+ },
+ .pub_key = rsa1024_public_key,
+ .pub_key_len = sizeof(rsa1024_public_key),
+ .priv_key = rsa1024_private_key,
+ .priv_key_len = sizeof(rsa1024_private_key),
+
+ .plaintext = test_plaintext,
+ .plen = 128,
+ .ciphertext = exp_ciphertext_rsa1024_raw,
+ .clen = sizeof(exp_ciphertext_rsa1024_raw),
+ },
+
+ /* rsa1024 with pkcs1 padding */
+ {
+ .path = "/crypto/akcipher/rsa1024-pkcs1",
+ .opt = {
+ .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .u.rsa = {
+ .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ },
+ },
+ .pub_key = rsa1024_public_key,
+ .pub_key_len = sizeof(rsa1024_public_key),
+ .priv_key = rsa1024_private_key,
+ .priv_key_len = sizeof(rsa1024_private_key),
+
+ .plaintext = test_plaintext,
+ .plen = 64,
+ .ciphertext = exp_ciphertext_rsa1024_pkcs1,
+ .clen = sizeof(exp_ciphertext_rsa1024_pkcs1),
+ .dgst = test_sha1_dgst,
+ .dlen = sizeof(test_sha1_dgst),
+ .signature = exp_signature_rsa1024_pkcs1,
+ .slen = sizeof(exp_signature_rsa1024_pkcs1),
+ },
+
+ /* rsa2048 with raw padding */
+ {
+ .path = "/crypto/akcipher/rsa2048-raw",
+ .opt = {
+ .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .u.rsa = {
+ .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW,
+ },
+ },
+ .pub_key = rsa2048_public_key,
+ .pub_key_len = sizeof(rsa2048_public_key),
+ .priv_key = rsa2048_private_key,
+ .priv_key_len = sizeof(rsa2048_private_key),
+
+ .plaintext = test_plaintext,
+ .plen = 256,
+ .ciphertext = exp_ciphertext_rsa2048_raw,
+ .clen = sizeof(exp_ciphertext_rsa2048_raw),
+ },
+
+ /* rsa2048 with pkcs1 padding */
+ {
+ .path = "/crypto/akcipher/rsa2048-pkcs1",
+ .opt = {
+ .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .u.rsa = {
+ .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ },
+ },
+ .pub_key = rsa2048_public_key,
+ .pub_key_len = sizeof(rsa2048_public_key),
+ .priv_key = rsa2048_private_key,
+ .priv_key_len = sizeof(rsa2048_private_key),
+
+ .plaintext = test_plaintext,
+ .plen = 128,
+ .ciphertext = exp_ciphertext_rsa2048_pkcs1,
+ .clen = sizeof(exp_ciphertext_rsa2048_pkcs1),
+ .dgst = test_sha1_dgst,
+ .dlen = sizeof(test_sha1_dgst),
+ .signature = exp_signature_rsa2048_pkcs1,
+ .slen = sizeof(exp_signature_rsa2048_pkcs1),
+ },
+
+};
+
+static void test_akcipher(const void *opaque)
+{
+ const QCryptoAkCipherTestData *data = opaque;
+ g_autofree uint8_t *plaintext = NULL;
+ g_autofree uint8_t *ciphertext = NULL;
+ g_autofree uint8_t *signature = NULL;
+ QCryptoAkCipher *pub_key, *priv_key;
+
+ if (!qcrypto_akcipher_supports((QCryptoAkCipherOptions *)&data->opt)) {
+ return;
+ }
+ pub_key = qcrypto_akcipher_new(&data->opt,
+ QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ data->pub_key, data->pub_key_len,
+ &error_abort);
+ g_assert(pub_key != NULL);
+ priv_key = qcrypto_akcipher_new(&data->opt,
+ QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ data->priv_key, data->priv_key_len,
+ &error_abort);
+ g_assert(priv_key != NULL);
+
+ if (data->plaintext != NULL) {
+
+ ciphertext = g_new0(uint8_t, data->clen);
+ g_assert(qcrypto_akcipher_encrypt(pub_key, data->plaintext, data->plen,
+ ciphertext, data->clen,
+ &error_abort) > 0);
+
+ /**
+ * In the asymmetric encryption algorithms, the ciphertext generated
+ * each time may be different, here only compare the decrypted
+ * plaintext
+ */
+ plaintext = g_new0(uint8_t, data->clen);
+ g_assert(qcrypto_akcipher_decrypt(priv_key, ciphertext,
+ data->clen, plaintext,
+ data->plen,
+ &error_abort) == data->plen);
+ g_assert(!memcmp(plaintext, data->plaintext, data->plen));
+ }
+
+ if (data->signature != NULL) {
+ signature = g_new(uint8_t, data->slen);
+ g_assert(qcrypto_akcipher_sign(priv_key, data->dgst, data->dlen,
+ signature, data->slen,
+ &error_abort) > 0);
+ /**
+ * The signature generated each time may be different, here only check
+ * the verification.
+ */
+ g_assert(qcrypto_akcipher_verify(pub_key, data->signature, data->slen,
+ data->dgst, data->dlen,
+ &error_abort) == 0);
+ g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+ data->dgst, data->dlen,
+ &error_abort) == 0);
+ ++signature[0];
+ /* Here error should be ignored */
+ g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+ data->dgst, data->dlen, NULL) != 0);
+ }
+
+ qcrypto_akcipher_free(pub_key);
+ qcrypto_akcipher_free(priv_key);
+}
+
+int main(int argc, char **argv)
+{
+ size_t i;
+ g_test_init(&argc, &argv, NULL);
+ g_assert(qcrypto_init(NULL) == 0);
+
+ for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
+ g_test_add_data_func(test_data[i].path, &test_data[i], test_akcipher);
+ }
+
+ return g_test_run();
+}
--
2.20.1


2022-05-14 04:25:29

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v6 3/9] crypto: Introduce akcipher crypto class

Introduce new akcipher crypto class 'QCryptoAkCIpher', which supports
basic asymmetric operations: encrypt, decrypt, sign and verify.

Suggested by Daniel P. Berrangé, also add autoptr cleanup for the new
class. Thanks to Daniel!

Co-developed-by: lei he <[email protected]>
Signed-off-by: lei he <[email protected]>
Signed-off-by: zhenwei pi <[email protected]>
Reviewed-by: Daniel P. Berrangé <[email protected]>
---
crypto/akcipher.c | 102 ++++++++++++++++++++++++
crypto/akcipherpriv.h | 55 +++++++++++++
crypto/meson.build | 1 +
include/crypto/akcipher.h | 158 ++++++++++++++++++++++++++++++++++++++
4 files changed, 316 insertions(+)
create mode 100644 crypto/akcipher.c
create mode 100644 crypto/akcipherpriv.h
create mode 100644 include/crypto/akcipher.h

diff --git a/crypto/akcipher.c b/crypto/akcipher.c
new file mode 100644
index 0000000000..ab28bf415b
--- /dev/null
+++ b/crypto/akcipher.c
@@ -0,0 +1,102 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/akcipher.h"
+#include "akcipherpriv.h"
+
+QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
+ QCryptoAkCipherKeyType type,
+ const uint8_t *key, size_t keylen,
+ Error **errp)
+{
+ QCryptoAkCipher *akcipher = NULL;
+
+ return akcipher;
+}
+
+bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts)
+{
+ return false;
+}
+
+int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp)
+{
+ const QCryptoAkCipherDriver *drv = akcipher->driver;
+
+ return drv->encrypt(akcipher, in, in_len, out, out_len, errp);
+}
+
+int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp)
+{
+ const QCryptoAkCipherDriver *drv = akcipher->driver;
+
+ return drv->decrypt(akcipher, in, in_len, out, out_len, errp);
+}
+
+int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp)
+{
+ const QCryptoAkCipherDriver *drv = akcipher->driver;
+
+ return drv->sign(akcipher, in, in_len, out, out_len, errp);
+}
+
+int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ const void *in2, size_t in2_len, Error **errp)
+{
+ const QCryptoAkCipherDriver *drv = akcipher->driver;
+
+ return drv->verify(akcipher, in, in_len, in2, in2_len, errp);
+}
+
+int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher)
+{
+ return akcipher->max_plaintext_len;
+}
+
+int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher)
+{
+ return akcipher->max_ciphertext_len;
+}
+
+int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher)
+{
+ return akcipher->max_signature_len;
+}
+
+int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher)
+{
+ return akcipher->max_dgst_len;
+}
+
+void qcrypto_akcipher_free(QCryptoAkCipher *akcipher)
+{
+ const QCryptoAkCipherDriver *drv = akcipher->driver;
+
+ drv->free(akcipher);
+}
diff --git a/crypto/akcipherpriv.h b/crypto/akcipherpriv.h
new file mode 100644
index 0000000000..739f639bcf
--- /dev/null
+++ b/crypto/akcipherpriv.h
@@ -0,0 +1,55 @@
+/*
+ * QEMU Crypto asymmetric algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_AKCIPHERPRIV_H
+#define QCRYPTO_AKCIPHERPRIV_H
+
+#include "qapi/qapi-types-crypto.h"
+
+typedef struct QCryptoAkCipherDriver QCryptoAkCipherDriver;
+
+struct QCryptoAkCipher {
+ QCryptoAkCipherAlgorithm alg;
+ QCryptoAkCipherKeyType type;
+ int max_plaintext_len;
+ int max_ciphertext_len;
+ int max_signature_len;
+ int max_dgst_len;
+ QCryptoAkCipherDriver *driver;
+};
+
+struct QCryptoAkCipherDriver {
+ int (*encrypt)(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp);
+ int (*decrypt)(QCryptoAkCipher *akcipher,
+ const void *out, size_t out_len,
+ void *in, size_t in_len, Error **errp);
+ int (*sign)(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp);
+ int (*verify)(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ const void *in2, size_t in2_len, Error **errp);
+ void (*free)(QCryptoAkCipher *akcipher);
+};
+
+#endif /* QCRYPTO_AKCIPHER_H */
diff --git a/crypto/meson.build b/crypto/meson.build
index 685fb37097..313f935f27 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -1,6 +1,7 @@
crypto_ss.add(genh)
crypto_ss.add(files(
'afsplit.c',
+ 'akcipher.c',
'block-luks.c',
'block-qcow.c',
'block.c',
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
new file mode 100644
index 0000000000..51f5fa2774
--- /dev/null
+++ b/include/crypto/akcipher.h
@@ -0,0 +1,158 @@
+/*
+ * QEMU Crypto asymmetric algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_AKCIPHER_H
+#define QCRYPTO_AKCIPHER_H
+
+#include "qapi/qapi-types-crypto.h"
+
+typedef struct QCryptoAkCipher QCryptoAkCipher;
+
+/**
+ * qcrypto_akcipher_supports:
+ * @opts: the asymmetric key algorithm and related options
+ *
+ * Determine if asymmetric key cipher decribed with @opts is
+ * supported by the current configured build
+ *
+ * Returns: true if it is supported, false otherwise.
+ */
+bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts);
+
+/**
+ * qcrypto_akcipher_new:
+ * @opts: specify the algorithm and the related arguments
+ * @type: private or public key type
+ * @key: buffer to store the key
+ * @key_len: the length of key buffer
+ * @errp: error pointer
+ *
+ * Create akcipher context
+ *
+ * Returns: On success, a new QCryptoAkCipher initialized with @opt
+ * is created and returned, otherwise NULL is returned.
+ */
+
+QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
+ QCryptoAkCipherKeyType type,
+ const uint8_t *key, size_t key_len,
+ Error **errp);
+
+/**
+ * qcrypto_akcipher_encrypt:
+ * @akcipher: akcipher context
+ * @in: plaintext pending to be encrypted
+ * @in_len: length of plaintext, less or equal to the size reported
+ * by a call to qcrypto_akcipher_max_plaintext_len()
+ * @out: buffer to store the ciphertext
+ * @out_len: length of ciphertext, less or equal to the size reported
+ * by a call to qcrypto_akcipher_max_ciphertext_len()
+ * @errp: error pointer
+ *
+ * Encrypt @in and write ciphertext into @out
+ *
+ * Returns: length of ciphertext if encrypt succeed,
+ * otherwise -1 is returned
+ */
+int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_decrypt:
+ * @akcipher: akcipher context
+ * @in: ciphertext to be decrypted
+ * @in_len: the length of ciphertext, less or equal to the size reported
+ * by a call to qcrypto_akcipher_max_ciphertext_len()
+ * @out: buffer to store the plaintext
+ * @out_len: length of the plaintext buffer, less or equal to the size
+ * reported by a call to qcrypto_akcipher_max_plaintext_len()
+ * @errp: error pointer
+ *
+ * Decrypt @in and write plaintext into @out
+ *
+ * Returns: length of plaintext if decrypt succeed,
+ * otherwise -1 is returned
+ */
+int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_sign:
+ * @akcipher: akcipher context
+ * @in: data to be signed
+ * @in_len: the length of data, less or equal to the size reported
+ * by a call to qcrypto_akcipher_max_dgst_len()
+ * @out: buffer to store the signature
+ * @out_len: length of the signature buffer, less or equal to the size
+ * by a call to qcrypto_akcipher_max_signature_len()
+ * @errp: error pointer
+ *
+ * Generate signature for @in, write into @out
+ *
+ * Returns: length of signature if succeed,
+ * otherwise -1 is returned
+ */
+int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ void *out, size_t out_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_verify:
+ * @akcipher: akcipher context
+ * @in: pointer to the signature
+ * @in_len: length of signature, ess or equal to the size reported
+ * by a call to qcrypto_akcipher_max_signature_len()
+ * @in2: pointer to original data
+ * @in2_len: the length of original data, less or equal to the size
+ * by a call to qcrypto_akcipher_max_dgst_len()
+ * @errp: error pointer
+ *
+ * Verify @in and @in2 match or not
+ *
+ * Returns: 0 for succeed,
+ * otherwise -1 is returned
+ */
+int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher,
+ const void *in, size_t in_len,
+ const void *in2, size_t in2_len, Error **errp);
+
+int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher);
+
+int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher);
+
+int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher);
+
+int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher);
+
+/**
+ * qcrypto_akcipher_free:
+ * @akcipher: akcipher context
+ *
+ * Free the akcipher context
+ *
+ */
+void qcrypto_akcipher_free(QCryptoAkCipher *akcipher);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipher, qcrypto_akcipher_free)
+
+#endif /* QCRYPTO_AKCIPHER_H */
--
2.20.1


2022-05-14 04:25:31

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v6 4/9] crypto: add ASN.1 DER decoder

From: Lei He <[email protected]>

Add an ANS.1 DER decoder which is used to parse asymmetric
cipher keys

Signed-off-by: zhenwei pi <[email protected]>
Signed-off-by: lei he <[email protected]>
---
crypto/der.c | 189 +++++++++++++++++++++++
crypto/der.h | 81 ++++++++++
crypto/meson.build | 1 +
tests/unit/meson.build | 1 +
tests/unit/test-crypto-der.c | 290 +++++++++++++++++++++++++++++++++++
5 files changed, 562 insertions(+)
create mode 100644 crypto/der.c
create mode 100644 crypto/der.h
create mode 100644 tests/unit/test-crypto-der.c

diff --git a/crypto/der.c b/crypto/der.c
new file mode 100644
index 0000000000..721bbb3317
--- /dev/null
+++ b/crypto/der.c
@@ -0,0 +1,189 @@
+/*
+ * QEMU Crypto ASN.1 DER decoder
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/der.h"
+
+enum QCryptoDERTypeTag {
+ QCRYPTO_DER_TYPE_TAG_BOOL = 0x1,
+ QCRYPTO_DER_TYPE_TAG_INT = 0x2,
+ QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3,
+ QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4,
+ QCRYPTO_DER_TYPE_TAG_OCT_NULL = 0x5,
+ QCRYPTO_DER_TYPE_TAG_OCT_OID = 0x6,
+ QCRYPTO_DER_TYPE_TAG_SEQ = 0x10,
+ QCRYPTO_DER_TYPE_TAG_SET = 0x11,
+};
+
+#define QCRYPTO_DER_CONSTRUCTED_MASK 0x20
+#define QCRYPTO_DER_SHORT_LEN_MASK 0x80
+
+static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
+{
+ return **data;
+}
+
+static void qcrypto_der_cut_nbytes(const uint8_t **data,
+ size_t *dlen,
+ size_t nbytes)
+{
+ *data += nbytes;
+ *dlen -= nbytes;
+}
+
+static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen)
+{
+ uint8_t val = qcrypto_der_peek_byte(data, dlen);
+
+ qcrypto_der_cut_nbytes(data, dlen, 1);
+
+ return val;
+}
+
+static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx,
+ const uint8_t *value, size_t vlen,
+ Error **errp)
+{
+ if (!cb) {
+ return 0;
+ }
+
+ return cb(ctx, value, vlen, errp);
+}
+
+static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen,
+ QCryptoDERDecodeCb cb, void *ctx,
+ Error **errp)
+{
+ const uint8_t *value;
+ size_t vlen = 0;
+ uint8_t byte_count = qcrypto_der_cut_byte(data, dlen);
+
+ /* short format of definite-length */
+ if (!(byte_count & QCRYPTO_DER_SHORT_LEN_MASK)) {
+ if (byte_count > *dlen) {
+ error_setg(errp, "Invalid content length: %u", byte_count);
+ return -1;
+ }
+
+ value = *data;
+ vlen = byte_count;
+ qcrypto_der_cut_nbytes(data, dlen, vlen);
+
+ if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
+ return -1;
+ }
+ return vlen;
+ }
+
+ /* Ignore highest bit */
+ byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK;
+
+ /*
+ * size_t is enough to store the value of length, although the DER
+ * encoding standard supports larger length.
+ */
+ if (byte_count > sizeof(size_t)) {
+ error_setg(errp, "Invalid byte count of content length: %u",
+ byte_count);
+ return -1;
+ }
+
+ if (byte_count > *dlen) {
+ error_setg(errp, "Invalid content length: %u", byte_count);
+ return -1;
+ }
+ while (byte_count--) {
+ vlen <<= 8;
+ vlen += qcrypto_der_cut_byte(data, dlen);
+ }
+
+ if (vlen > *dlen) {
+ error_setg(errp, "Invalid content length: %lu", vlen);
+ return -1;
+ }
+
+ value = *data;
+ qcrypto_der_cut_nbytes(data, dlen, vlen);
+
+ if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
+ return -1;
+ }
+ return vlen;
+}
+
+static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen,
+ QCryptoDERDecodeCb cb, void *ctx,
+ Error **errp)
+{
+ uint8_t val;
+ if (*dlen < 1) {
+ error_setg(errp, "Need more data");
+ return -1;
+ }
+ val = qcrypto_der_peek_byte(data, dlen);
+
+ /* must use definite length format */
+ if (val == QCRYPTO_DER_SHORT_LEN_MASK) {
+ error_setg(errp, "Only definite length format is allowed");
+ return -1;
+ }
+
+ return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp);
+}
+
+int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen,
+ QCryptoDERDecodeCb cb, void *ctx, Error **errp)
+{
+ uint8_t tag;
+ if (*dlen < 1) {
+ error_setg(errp, "Need more data");
+ return -1;
+ }
+ tag = qcrypto_der_cut_byte(data, dlen);
+
+ /* INTEGER must encoded in primitive-form */
+ if (tag != QCRYPTO_DER_TYPE_TAG_INT) {
+ error_setg(errp, "Invalid integer type tag: %u", tag);
+ return -1;
+ }
+
+ return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
+}
+
+int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen,
+ QCryptoDERDecodeCb cb, void *ctx, Error **errp)
+{
+ uint8_t tag;
+ if (*dlen < 1) {
+ error_setg(errp, "Need more data");
+ return -1;
+ }
+ tag = qcrypto_der_cut_byte(data, dlen);
+
+ /* SEQUENCE must use constructed form */
+ if (tag != (QCRYPTO_DER_TYPE_TAG_SEQ | QCRYPTO_DER_CONSTRUCTED_MASK)) {
+ error_setg(errp, "Invalid type sequence tag: %u", tag);
+ return -1;
+ }
+
+ return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
+}
diff --git a/crypto/der.h b/crypto/der.h
new file mode 100644
index 0000000000..e3d3aeacdc
--- /dev/null
+++ b/crypto/der.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_ASN1_DECODER_H
+#define QCRYPTO_ASN1_DECODER_H
+
+#include "qapi/error.h"
+
+/* Simple decoder used to parse DER encoded rsa keys. */
+
+/**
+ * @opaque: user context.
+ * @value: the starting address of |value| part of 'Tag-Length-Value' pattern.
+ * @vlen: length of the |value|.
+ * Returns: 0 for success, any other value is considered an error.
+ */
+typedef int (*QCryptoDERDecodeCb) (void *opaque, const uint8_t *value,
+ size_t vlen, Error **errp);
+
+/**
+ * qcrypto_der_decode_int:
+ * @data: pointer to address of input data
+ * @dlen: pointer to length of input data
+ * @cb: callback invoked when decode succeed, if cb equals NULL, no
+ * callback will be invoked
+ * @opaque: parameter passed to cb
+ *
+ * Decode integer from DER-encoded data.
+ *
+ * Returns: On success, *data points to rest data, and *dlen
+ * will be set to the rest length of data, if cb is not NULL, must
+ * return 0 to make decode success, at last, the length of the data
+ * part of the decoded INTEGER will be returned. Otherwise, -1 is
+ * returned.
+ */
+int qcrypto_der_decode_int(const uint8_t **data,
+ size_t *dlen,
+ QCryptoDERDecodeCb cb,
+ void *opaque,
+ Error **errp);
+
+/**
+ * qcrypto_der_decode_seq:
+ *
+ * Decode sequence from DER-encoded data, similar with der_decode_int.
+ *
+ * @data: pointer to address of input data
+ * @dlen: pointer to length of input data
+ * @cb: callback invoked when decode succeed, if cb equals NULL, no
+ * callback will be invoked
+ * @opaque: parameter passed to cb
+ *
+ * Returns: On success, *data points to rest data, and *dlen
+ * will be set to the rest length of data, if cb is not NULL, must
+ * return 0 to make decode success, at last, the length of the data
+ * part of the decoded SEQUENCE will be returned. Otherwise, -1 is
+ * returned.
+ */
+int qcrypto_der_decode_seq(const uint8_t **data,
+ size_t *dlen,
+ QCryptoDERDecodeCb cb,
+ void *opaque,
+ Error **errp);
+
+#endif /* QCRYPTO_ASN1_DECODER_H */
diff --git a/crypto/meson.build b/crypto/meson.build
index 313f935f27..b8152ae7cb 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -6,6 +6,7 @@ crypto_ss.add(files(
'block-qcow.c',
'block.c',
'cipher.c',
+ 'der.c',
'hash.c',
'hmac.c',
'ivgen-essiv.c',
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 264f2bc0c8..a8af85128d 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -47,6 +47,7 @@ tests = {
'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'],
'test-qapi-util': [],
'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine-smp.c'],
+ 'test-crypto-der': [crypto],
}

if have_system or have_tools
diff --git a/tests/unit/test-crypto-der.c b/tests/unit/test-crypto-der.c
new file mode 100644
index 0000000000..aed0f28d68
--- /dev/null
+++ b/tests/unit/test-crypto-der.c
@@ -0,0 +1,290 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/der.h"
+
+/* rsa(512) private key, generated by openssl */
+static const uint8_t test_rsa512_priv_key[] =
+ "\x30\x82\x01\x39" /* SEQUENCE, offset: 0, length: 313 */
+ "\x02\x01\x00" /* INTEGER, offset: 4, length: 1 */
+ "\x02\x41" /* INTEGER, offset: 7, length: 65 */
+ "\x00\xb9\xe1\x22\xdb\x56\x2f\xb6\xf7\xf0\x0a\x87\x43\x07\x12\xdb"
+ "\x6d\xb6\x2b\x41\x8d\x2c\x3c\xa5\xdd\x78\x9a\x8f\xab\x8e\xf2\x4a"
+ "\xc8\x34\x0c\x12\x4f\x11\x90\xc6\xc2\xa5\xd0\xcd\xfb\xfc\x2c\x95"
+ "\x56\x82\xdf\x39\xf3\x3b\x1d\x62\x26\x97\xb7\x93\x25\xc7\xec\x7e"
+ "\xf7"
+ "\x02\x03\x01\x00\x01" /* INTEGER, offset: 74, length: 3 */
+ "\x02\x40" /* INTEGER, offset: 79, length: 64 */
+ "\x1e\x80\xfe\xda\x65\xdb\x70\xb8\x61\x91\x28\xbf\x6c\x32\xc1\x05"
+ "\xd1\x26\x6a\x1c\x83\xcc\xf4\x1f\x53\x42\x72\x1f\x62\x57\x0a\xc4"
+ "\x66\x76\x30\x87\xb9\xb1\xb9\x6a\x63\xfd\x8f\x3e\xfc\x35\x3f\xd6"
+ "\x2e\x6c\xc8\x70\x8a\x17\xc1\x28\x6a\xfe\x51\x56\xb3\x92\x6f\x09"
+ "\x02\x21" /* INTEGER, offset: 145, length: 33 */
+ "\x00\xe3\x2e\x2d\x8d\xba\x1c\x34\x4c\x49\x9f\xc1\xa6\xdd\xd7\x13"
+ "\x8d\x05\x48\xdd\xff\x5c\x30\xbc\x6b\xc4\x18\x9d\xfc\xa2\xd0\x9b"
+ "\x4d"
+ "\x02\x21" /* INTEGER, offset: 180, length: 33 */
+ "\x00\xd1\x75\xaf\x4b\xc6\x1a\xb0\x98\x14\x42\xae\x33\xf3\x44\xde"
+ "\x21\xcb\x04\xda\xfb\x1e\x35\x92\xcd\x69\xc0\x83\x06\x83\x8e\x39"
+ "\x53"
+ "\x02\x20" /* INTEGER, offset: 215, length: 32 */
+ "\x68\x8d\x2a\xf7\xcb\xcc\x09\x21\x86\xcc\x98\x21\xc4\x7c\xa4\x09"
+ "\xc5\x81\xd8\x71\x1a\x2b\x6f\xbb\xa4\xde\xb3\x6e\xbe\x3b\x85\x0d"
+ "\x02\x20" /* INTEGER, offset: 249, length: 32 */
+ "\x64\x06\x0e\xef\xe0\x6a\x5e\x6a\x41\x42\x96\x6d\xb8\x7d\xea\x95"
+ "\xb8\x9d\x58\xf5\x12\x38\x03\x22\x94\x9d\x99\xf4\x42\x5e\x68\x81"
+ "\x02\x20" /* INTEGER, offset: 283, length: 32 */
+ "\x7f\x1d\x87\xe8\x55\x30\x75\xc7\x29\xec\xc9\x65\x76\x5a\x6a\xa3"
+ "\x4a\x6e\xe1\x26\x65\xd1\x76\xd5\xb9\xd1\x8b\xa8\x73\xe2\x6a\x9e";
+
+static const uint8_t test_rsa2048_priv_key[] =
+ "\x30\x82\x04\xa6" /* SEQUENCE, offset: 0, length 1190 */
+ "\x02\x01\x00" /* INTEGER, offset: 4, length: 1 */
+ "\x02\x82\x01\x01" /* INTEGER, offset: 7, length: 257 */
+ "\x00\xd1\x48\xc2\xc1\x1d\x4f\x94\xf2\xbb\x9b\xe2\x2d\xe1\xea\x4c"
+ "\xce\x41\x72\xe3\x41\x7e\x9d\x91\x85\xa3\x4e\xe1\x2c\xf6\x52\x6d"
+ "\xf9\x84\x64\xdf\x87\x28\x4a\xc9\x9d\x78\x93\x47\xc8\xd9\x66\x2e"
+ "\xf4\xc6\xf0\x32\x15\x1a\xe8\xaf\x5a\xca\x3a\xd3\x3e\xf6\xde\x86"
+ "\xdd\x9b\xa6\x4d\x74\x58\xf0\x11\x7f\x66\xd5\x1c\xd8\xde\xa3\xf8"
+ "\xa3\xfc\x33\x55\x89\xa9\xc3\xea\x5b\x2e\x31\x06\xf8\xcb\x9e\x6e"
+ "\xb2\x68\x0d\xe6\xc3\x5c\x2d\xf8\xa2\xbd\x00\x1a\xf6\xb6\xdd\x14"
+ "\x8d\x11\x6d\x2d\xc6\x0c\x09\xe6\xf6\xb9\x8b\x87\x4c\x9f\x4d\x63"
+ "\xd3\x94\xf4\x32\xca\xcf\x5e\xbf\xe2\x7f\x73\x5a\x65\xec\x82\x0d"
+ "\x7f\x30\x25\x03\xd4\x3a\xff\xa2\xe8\xd6\xb5\x1f\x4f\x36\x64\x61"
+ "\xc3\x5f\xb2\x9e\x0c\x53\x04\x19\x34\x99\xe8\xe3\xe6\xd3\x2f\x45"
+ "\x58\x8e\x5d\x54\x5a\xa0\xc0\x5e\x51\x9b\x22\x15\xec\x26\x6f\x72"
+ "\x68\xe9\xbf\x5d\x1d\xb5\xd9\xe4\x81\x1a\x92\x66\xa8\xcb\x73\x46"
+ "\xab\x96\x7b\xf8\x9c\xf5\xb5\x9e\x2b\x13\x71\xe0\x01\x0c\x59\x1b"
+ "\x63\x9f\xb7\xd1\xcd\x47\x8e\xc7\x3a\xbe\xcb\x47\xa7\x23\x43\xa7"
+ "\x7d\xbd\x2c\x4e\x22\x37\xcc\xf9\x1b\x1b\xbb\xed\xec\xf0\x47\x92"
+ "\x43"
+ "\x02\x03\x01\x00\x01" /* INTEGER, offset 268, length 3 */
+ "\x02\x82\x01\x01" /* INTEGER, offset 273, length 257 */
+ "\x00\x8d\x21\x97\x0c\x29\x9a\xf8\x23\xf4\x76\x3b\xc1\x9b\x3e\xa8"
+ "\x8a\xd2\xc2\x0a\x14\xa9\xb0\xd2\x68\x9f\x67\x5b\x1c\x3a\x03\xfe"
+ "\x5b\xac\x77\x65\xf1\xbc\x2f\x2a\xe5\x01\x61\xb8\x9f\xee\x53\x25"
+ "\x49\x36\x3a\xd6\x5b\x3b\x29\x3c\xcf\x69\xde\xdf\x83\xef\x70\xc2"
+ "\xdc\x00\xd1\xd6\x1b\xa6\xba\x45\xe2\x77\x53\x31\xbf\xe1\xec\x0b"
+ "\x89\x72\x52\x9f\xd5\x54\xe1\x64\x52\x16\xc5\x43\x21\x56\x16\xc2"
+ "\x29\x97\x58\x00\x8d\x2f\xc5\x64\x8d\x42\x0d\x27\x21\xc6\xd1\x31"
+ "\xc1\xab\xc5\xc7\x7f\x6d\xb0\xe3\xca\xef\xf6\xf2\xc7\xae\x09\xbf"
+ "\x4d\xc0\x4e\x90\x2c\x28\xb9\xcc\x22\x74\xf2\xd5\xff\x4d\x86\xf6"
+ "\xec\x45\x1f\xbf\x25\x4c\x30\x26\x76\x4f\x09\x13\x83\xef\x35\x73"
+ "\xa3\xa2\xb1\x40\xcf\x07\x7a\x83\xae\xea\x00\xea\x74\xc7\x54\x6a"
+ "\x88\x19\xed\x35\xd3\x7e\x5e\xac\x51\xc1\x1e\x5e\x2c\x57\x72\x20"
+ "\x10\x6a\x0c\x47\xe1\xf0\x36\x70\xd2\xa7\x57\x64\x47\x46\x9f\xca"
+ "\x23\x8a\x48\x50\x1d\x33\x6a\x86\x46\x69\xed\x54\x65\x6b\x9e\xab"
+ "\x1f\x84\x87\xf4\x92\x8a\x6c\x44\x20\xaa\x8d\xd8\x50\xde\x45\x74"
+ "\xe0\xa8\xc7\xb9\x38\x74\x24\x51\x33\xf0\x39\x54\x6c\x11\xae\xc2"
+ "\x29"
+ "\x02\x81\x81" /* INTEGER, offset 534, length 129 */
+ "\x00\xe8\x26\xd1\xf9\xa0\xd3\x0e\x3f\x2f\x89\x9b\x94\x16\x12\xd1"
+ "\xae\x3c\x53\x9c\xcf\xc6\xf7\x03\xf5\xdf\x39\xdc\x25\x5d\xcb\xb8"
+ "\xb9\x74\x3e\x3b\x36\xf6\xa0\x8d\xb1\x0e\xd8\xfe\x8c\xcd\x01\x13"
+ "\x77\x73\x08\x0f\x32\xbd\xe6\x95\xdc\xd0\x14\x7d\x44\xdc\x3e\xd9"
+ "\xaa\x8a\x32\xe6\x0e\x76\xb6\x05\xc5\x6b\x87\x78\x9a\x32\xe2\xf8"
+ "\x78\xba\x58\x75\x58\xd5\x26\x9d\x9a\x0f\xb6\xca\xb5\x27\xd8\x58"
+ "\xae\x3f\x49\x54\xd2\x2b\xac\x28\x39\x88\x31\x42\x12\x08\xea\x0b"
+ "\x39\x58\xae\xf3\x82\xa0\xe2\x75\x7c\x96\xa9\xb8\x57\x29\x6d\xd7"
+ "\x37"
+ "\x02\x81\x81" /* INTEGER, offset 666, length 129 */
+ "\x00\xe6\xc8\x91\x50\x49\x97\x56\x70\x6e\x25\xf5\x77\x25\xa5\x41"
+ "\xfe\xd7\x25\x1b\xc1\x4a\xff\x37\x44\x2b\x46\xa0\xdf\xe8\x02\x09"
+ "\xdd\xa8\x41\xa1\x12\x84\x3c\xf8\xc2\x13\x3e\xb8\x4b\x22\x01\xac"
+ "\xa6\x09\xb2\xe9\xcd\xc8\x51\xee\xde\xa3\x1e\x6b\xfe\xb1\xf8\xb6"
+ "\x9e\x48\x36\x62\x0b\x05\xfa\x38\xc1\x06\x04\x58\x95\x4d\x25\x13"
+ "\x6d\x0b\x12\x0b\xc9\x6d\x59\xfc\x33\x03\x36\x01\x12\x09\x72\x74"
+ "\x5e\x98\x65\x66\x2f\x3a\xde\xd8\xd4\xee\x6f\x82\xe6\x36\x49\x12"
+ "\x6a\x94\x28\xe9\x28\x9e\xef\x29\xdc\xdf\xab\x94\x65\x02\x4e\x4b"
+ "\x55"
+ "\x02\x81\x81" /* INTEGER, offset 798, length 129 */
+ "\x00\xc9\xda\xb7\x48\x6e\x66\x15\x45\x2b\x78\x63\x26\x67\xeb\x05"
+ "\x16\x92\xad\xc0\xf3\x88\xf4\xcf\x24\xc2\x6b\xf4\xd7\x28\xaf\x32"
+ "\x77\x4e\x73\xad\xd9\x24\xa8\x85\x8b\x26\x75\xd7\x1f\x66\x41\x41"
+ "\x43\xe3\x69\x66\x8d\xa0\x41\x16\x9d\x60\xef\xef\xdc\x28\x05\x1e"
+ "\x0e\x03\x0c\x2e\xac\xf4\xdb\x60\x39\x40\x3e\x12\xc7\x40\xe7\xc9"
+ "\x54\x6f\xf2\xea\x55\xcb\x40\x40\x58\xec\xc0\xeb\x90\x88\x8c\xbc"
+ "\xcf\x05\x88\x25\x90\x79\x18\xc0\x01\x06\x42\x8e\x48\x50\x27\xf0"
+ "\x8a\x74\x69\xea\xa1\xf2\x71\xf5\xe5\xd6\xba\xcb\xe6\x3d\xc7\x9c"
+ "\x11"
+ "\x02\x81\x81" /* INTEGER, offset 930, length 129 */
+ "\x00\xc9\xf5\x04\xad\x34\xe9\x39\xdc\x83\x97\xb6\x3a\x40\xf8\x60"
+ "\x4b\x69\xec\xf0\x5f\xf3\x88\x69\xcd\xbe\xed\x3c\xc5\x14\x5c\x0c"
+ "\x54\x2b\xf4\xda\xc6\xc0\x70\x36\xe4\x67\x41\x00\xb7\xc7\x17\x9e"
+ "\x05\x63\x01\x6d\x77\x06\x71\x24\xcf\x32\x01\xe2\x51\xed\x5e\x90"
+ "\x38\xed\x4a\xa1\xfb\xb1\x8c\x69\xf4\x08\x96\xef\x0a\x20\x8b\x6c"
+ "\x77\x85\x33\x92\x9a\xff\x95\xba\x8c\xcd\xa7\x89\xc2\x46\x00\x21"
+ "\xf3\xd1\xfb\x12\x34\x0c\x99\x8d\x38\xb1\x3b\x66\x5a\x9d\x70\xce"
+ "\xab\xf3\xe1\xe5\x40\x05\xed\x97\x3d\xd1\x82\x6e\x07\x02\xc0\x8f"
+ "\x4d"
+ "\x02\x81\x81" /* INTEGER, offset 1062, length 129 */
+ "\x00\xe4\x96\x79\xa8\x6a\x70\xdd\x67\x42\xff\x15\x11\x9e\x01\x71"
+ "\xac\xf1\x70\x7d\x87\xe2\x6e\x0c\x4d\xbb\x21\x15\xbb\xa7\x4e\x0c"
+ "\x09\x7e\x82\xca\x91\xbe\xd0\xdd\x9c\x8c\xb0\x77\x64\x30\x1b\x7e"
+ "\xbb\x69\xcb\x4c\xde\xd6\x6a\xb9\x72\x15\x79\xdc\x05\x99\x69\x8b"
+ "\x24\xa1\xad\x13\x35\x31\xc0\x0b\xf1\xd2\x06\x7c\x94\x1a\x21\x2f"
+ "\x02\xb9\xf0\xd0\xbb\xf7\xb7\x78\xf9\x3d\x76\x60\xd6\x6b\x5f\x35"
+ "\x88\x14\x33\xe6\xbc\xca\x6b\x88\x90\x57\x3b\x0c\xa3\x6e\x47\xdf"
+ "\x4e\x2f\x4c\xf9\xab\x97\x38\xe4\x20\x32\x32\x96\xc8\x9e\x79\xd3"
+ "\x12";
+
+#define MAX_CHECKER_COUNT 32
+
+typedef struct QCryptoAns1DecoderResultChecker QCryptoAns1DecoderResultChecker;
+struct QCryptoAns1DecoderResultChecker {
+ int (*action) (const uint8_t **data, size_t *dlen,
+ QCryptoDERDecodeCb cb, void *opaque, Error **errp);
+ QCryptoDERDecodeCb cb;
+ const uint8_t *exp_value;
+ size_t exp_vlen;
+};
+
+typedef struct QCryptoAns1DecoderTestData QCryptoAns1DecoderTestData;
+struct QCryptoAns1DecoderTestData {
+ const char *path;
+ const uint8_t *test_data;
+ size_t test_data_len;
+ QCryptoAns1DecoderResultChecker checker[MAX_CHECKER_COUNT];
+};
+
+typedef struct QCryptoAns1DecoderTestContext QCryptoAns1DecoderTestContext;
+struct QCryptoAns1DecoderTestContext {
+ const uint8_t *data;
+ size_t dlen;
+};
+
+static int checker_callback(void *opaque, const uint8_t *value,
+ size_t vlen, Error **errp)
+{
+ QCryptoAns1DecoderResultChecker *checker =
+ (QCryptoAns1DecoderResultChecker *)opaque;
+
+ g_assert(value == checker->exp_value);
+ g_assert(vlen == checker->exp_vlen);
+ return 0;
+}
+
+static void test_ans1(const void *opaque)
+{
+ const QCryptoAns1DecoderTestData *test_data =
+ (QCryptoAns1DecoderTestData *)opaque;
+ QCryptoAns1DecoderTestContext ctx[MAX_CHECKER_COUNT];
+ int seq_depth = 0, checker_idx = 0;
+ ctx[seq_depth].data = test_data->test_data;
+ ctx[seq_depth].dlen = test_data->test_data_len;
+ bool all_checker_completed = false;
+
+ do {
+ const QCryptoAns1DecoderResultChecker *checker =
+ &test_data->checker[checker_idx++];
+ QCryptoAns1DecoderTestContext *c = &ctx[seq_depth];
+ if (!checker->action) {
+ all_checker_completed = true;
+ break;
+ }
+ g_assert(checker->action(&c->data, &c->dlen, checker_callback,
+ (void *)checker, &error_abort)
+ == checker->exp_vlen);
+ if (checker->action == qcrypto_der_decode_seq) {
+ ++seq_depth;
+ ctx[seq_depth].data = checker->exp_value;
+ ctx[seq_depth].dlen = checker->exp_vlen;
+ }
+ while (seq_depth != 0 && ctx[seq_depth].dlen == 0) {
+ --seq_depth;
+ }
+
+ } while (true);
+ g_assert(seq_depth == 0);
+ g_assert(ctx[seq_depth].dlen == 0);
+ g_assert(all_checker_completed);
+}
+
+static QCryptoAns1DecoderTestData test_data[] = {
+{
+ .path = "/crypto/der/parse-rsa512-priv-key",
+ .test_data = test_rsa512_priv_key,
+ .test_data_len = sizeof(test_rsa512_priv_key) - 1,
+ .checker = {
+ { qcrypto_der_decode_seq, checker_callback,
+ test_rsa512_priv_key + 4, 313 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 4 + 2, 1 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 7 + 2, 65 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 74 + 2, 3 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 79 + 2, 64 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 145 + 2, 33 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 180 + 2, 33 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 215 + 2, 32 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 249 + 2, 32 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa512_priv_key + 283 + 2, 32 },
+ },
+},
+{
+ .path = "/crypto/der/parse-rsa2048-priv-key",
+ .test_data = test_rsa2048_priv_key,
+ .test_data_len = sizeof(test_rsa2048_priv_key) - 1,
+ .checker = {
+ { qcrypto_der_decode_seq, checker_callback,
+ test_rsa2048_priv_key + 4, 1190 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 4 + 2, 1 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 7 + 4, 257 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 268 + 2, 3 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 273 + 4, 257 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 534 + 3, 129 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 666 + 3, 129 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 798 + 3, 129 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 930 + 3, 129 },
+ { qcrypto_der_decode_int, checker_callback,
+ test_rsa2048_priv_key + 1062 + 3, 129 },
+ },
+},
+
+};
+
+int main(int argc, char **argv)
+{
+ size_t i;
+ g_test_init(&argc, &argv, NULL);
+
+ for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
+ g_test_add_data_func(test_data[i].path, &test_data[i], test_ans1);
+ }
+
+ return g_test_run();
+}
--
2.20.1


2022-05-14 04:25:33

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v6 1/9] virtio-crypto: header update

Update header from linux, support akcipher service.

Reviewed-by: Daniel P. Berrangé <[email protected]>
Reviewed-by: Gonglei <[email protected]>
Signed-off-by: lei he <[email protected]>
Signed-off-by: zhenwei pi <[email protected]>
---
.../standard-headers/linux/virtio_crypto.h | 82 ++++++++++++++++++-
1 file changed, 81 insertions(+), 1 deletion(-)

diff --git a/include/standard-headers/linux/virtio_crypto.h b/include/standard-headers/linux/virtio_crypto.h
index 5ff0b4ee59..68066dafb6 100644
--- a/include/standard-headers/linux/virtio_crypto.h
+++ b/include/standard-headers/linux/virtio_crypto.h
@@ -37,6 +37,7 @@
#define VIRTIO_CRYPTO_SERVICE_HASH 1
#define VIRTIO_CRYPTO_SERVICE_MAC 2
#define VIRTIO_CRYPTO_SERVICE_AEAD 3
+#define VIRTIO_CRYPTO_SERVICE_AKCIPHER 4

#define VIRTIO_CRYPTO_OPCODE(service, op) (((service) << 8) | (op))

@@ -57,6 +58,10 @@ struct virtio_crypto_ctrl_header {
VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02)
#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \
VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03)
+#define VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x04)
+#define VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x05)
uint32_t opcode;
uint32_t algo;
uint32_t flag;
@@ -180,6 +185,58 @@ struct virtio_crypto_aead_create_session_req {
uint8_t padding[32];
};

+struct virtio_crypto_rsa_session_para {
+#define VIRTIO_CRYPTO_RSA_RAW_PADDING 0
+#define VIRTIO_CRYPTO_RSA_PKCS1_PADDING 1
+ uint32_t padding_algo;
+
+#define VIRTIO_CRYPTO_RSA_NO_HASH 0
+#define VIRTIO_CRYPTO_RSA_MD2 1
+#define VIRTIO_CRYPTO_RSA_MD3 2
+#define VIRTIO_CRYPTO_RSA_MD4 3
+#define VIRTIO_CRYPTO_RSA_MD5 4
+#define VIRTIO_CRYPTO_RSA_SHA1 5
+#define VIRTIO_CRYPTO_RSA_SHA256 6
+#define VIRTIO_CRYPTO_RSA_SHA384 7
+#define VIRTIO_CRYPTO_RSA_SHA512 8
+#define VIRTIO_CRYPTO_RSA_SHA224 9
+ uint32_t hash_algo;
+};
+
+struct virtio_crypto_ecdsa_session_para {
+#define VIRTIO_CRYPTO_CURVE_UNKNOWN 0
+#define VIRTIO_CRYPTO_CURVE_NIST_P192 1
+#define VIRTIO_CRYPTO_CURVE_NIST_P224 2
+#define VIRTIO_CRYPTO_CURVE_NIST_P256 3
+#define VIRTIO_CRYPTO_CURVE_NIST_P384 4
+#define VIRTIO_CRYPTO_CURVE_NIST_P521 5
+ uint32_t curve_id;
+ uint32_t padding;
+};
+
+struct virtio_crypto_akcipher_session_para {
+#define VIRTIO_CRYPTO_NO_AKCIPHER 0
+#define VIRTIO_CRYPTO_AKCIPHER_RSA 1
+#define VIRTIO_CRYPTO_AKCIPHER_DSA 2
+#define VIRTIO_CRYPTO_AKCIPHER_ECDSA 3
+ uint32_t algo;
+
+#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC 1
+#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE 2
+ uint32_t keytype;
+ uint32_t keylen;
+
+ union {
+ struct virtio_crypto_rsa_session_para rsa;
+ struct virtio_crypto_ecdsa_session_para ecdsa;
+ } u;
+};
+
+struct virtio_crypto_akcipher_create_session_req {
+ struct virtio_crypto_akcipher_session_para para;
+ uint8_t padding[36];
+};
+
struct virtio_crypto_alg_chain_session_para {
#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1
#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2
@@ -247,6 +304,8 @@ struct virtio_crypto_op_ctrl_req {
mac_create_session;
struct virtio_crypto_aead_create_session_req
aead_create_session;
+ struct virtio_crypto_akcipher_create_session_req
+ akcipher_create_session;
struct virtio_crypto_destroy_session_req
destroy_session;
uint8_t padding[56];
@@ -266,6 +325,14 @@ struct virtio_crypto_op_header {
VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00)
#define VIRTIO_CRYPTO_AEAD_DECRYPT \
VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01)
+#define VIRTIO_CRYPTO_AKCIPHER_ENCRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x00)
+#define VIRTIO_CRYPTO_AKCIPHER_DECRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x01)
+#define VIRTIO_CRYPTO_AKCIPHER_SIGN \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x02)
+#define VIRTIO_CRYPTO_AKCIPHER_VERIFY \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x03)
uint32_t opcode;
/* algo should be service-specific algorithms */
uint32_t algo;
@@ -390,6 +457,16 @@ struct virtio_crypto_aead_data_req {
uint8_t padding[32];
};

+struct virtio_crypto_akcipher_para {
+ uint32_t src_data_len;
+ uint32_t dst_data_len;
+};
+
+struct virtio_crypto_akcipher_data_req {
+ struct virtio_crypto_akcipher_para para;
+ uint8_t padding[40];
+};
+
/* The request of the data virtqueue's packet */
struct virtio_crypto_op_data_req {
struct virtio_crypto_op_header header;
@@ -399,6 +476,7 @@ struct virtio_crypto_op_data_req {
struct virtio_crypto_hash_data_req hash_req;
struct virtio_crypto_mac_data_req mac_req;
struct virtio_crypto_aead_data_req aead_req;
+ struct virtio_crypto_akcipher_data_req akcipher_req;
uint8_t padding[48];
} u;
};
@@ -408,6 +486,8 @@ struct virtio_crypto_op_data_req {
#define VIRTIO_CRYPTO_BADMSG 2
#define VIRTIO_CRYPTO_NOTSUPP 3
#define VIRTIO_CRYPTO_INVSESS 4 /* Invalid session id */
+#define VIRTIO_CRYPTO_NOSPC 5 /* no free session ID */
+#define VIRTIO_CRYPTO_KEY_REJECTED 6 /* Signature verification failed */

/* The accelerator hardware is ready */
#define VIRTIO_CRYPTO_S_HW_READY (1 << 0)
@@ -438,7 +518,7 @@ struct virtio_crypto_config {
uint32_t max_cipher_key_len;
/* Maximum length of authenticated key */
uint32_t max_auth_key_len;
- uint32_t reserve;
+ uint32_t akcipher_algo;
/* Maximum size of each crypto request's content */
uint64_t max_size;
};
--
2.20.1


2022-05-14 04:26:05

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v6 5/9] crypto: Implement RSA algorithm by hogweed

From: Lei He <[email protected]>

Implement RSA algorithm by hogweed from nettle. Thus QEMU supports
a 'real' RSA backend to handle request from guest side. It's
important to test RSA offload case without OS & hardware requirement.

Signed-off-by: lei he <[email protected]>
Signed-off-by: zhenwei pi <[email protected]>
---
crypto/akcipher-nettle.c.inc | 451 +++++++++++++++++++++++++++++++++++
crypto/akcipher.c | 4 +
crypto/meson.build | 4 +
crypto/rsakey-builtin.c.inc | 200 ++++++++++++++++
crypto/rsakey-nettle.c.inc | 158 ++++++++++++
crypto/rsakey.c | 44 ++++
crypto/rsakey.h | 94 ++++++++
meson.build | 11 +
8 files changed, 966 insertions(+)
create mode 100644 crypto/akcipher-nettle.c.inc
create mode 100644 crypto/rsakey-builtin.c.inc
create mode 100644 crypto/rsakey-nettle.c.inc
create mode 100644 crypto/rsakey.c
create mode 100644 crypto/rsakey.h

diff --git a/crypto/akcipher-nettle.c.inc b/crypto/akcipher-nettle.c.inc
new file mode 100644
index 0000000000..0796bddcaa
--- /dev/null
+++ b/crypto/akcipher-nettle.c.inc
@@ -0,0 +1,451 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <nettle/rsa.h>
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "crypto/akcipher.h"
+#include "crypto/random.h"
+#include "qapi/error.h"
+#include "sysemu/cryptodev.h"
+#include "rsakey.h"
+
+typedef struct QCryptoNettleRSA {
+ QCryptoAkCipher akcipher;
+ struct rsa_public_key pub;
+ struct rsa_private_key priv;
+ QCryptoRSAPaddingAlgorithm padding_alg;
+ QCryptoHashAlgorithm hash_alg;
+} QCryptoNettleRSA;
+
+static void qcrypto_nettle_rsa_free(QCryptoAkCipher *akcipher)
+{
+ QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher;
+ if (!rsa) {
+ return;
+ }
+
+ rsa_public_key_clear(&rsa->pub);
+ rsa_private_key_clear(&rsa->priv);
+ g_free(rsa);
+}
+
+static QCryptoAkCipher *qcrypto_nettle_rsa_new(
+ const QCryptoAkCipherOptionsRSA *opt,
+ QCryptoAkCipherKeyType type,
+ const uint8_t *key, size_t keylen,
+ Error **errp);
+
+QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
+ QCryptoAkCipherKeyType type,
+ const uint8_t *key, size_t keylen,
+ Error **errp)
+{
+ switch (opts->alg) {
+ case QCRYPTO_AKCIPHER_ALG_RSA:
+ return qcrypto_nettle_rsa_new(&opts->u.rsa, type, key, keylen, errp);
+
+ default:
+ error_setg(errp, "Unsupported algorithm: %u", opts->alg);
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static void qcrypto_nettle_rsa_set_akcipher_size(QCryptoAkCipher *akcipher,
+ int key_size)
+{
+ akcipher->max_plaintext_len = key_size;
+ akcipher->max_ciphertext_len = key_size;
+ akcipher->max_signature_len = key_size;
+ akcipher->max_dgst_len = key_size;
+}
+
+static int qcrypt_nettle_parse_rsa_private_key(QCryptoNettleRSA *rsa,
+ const uint8_t *key,
+ size_t keylen,
+ Error **errp)
+{
+ g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
+ QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp);
+
+ if (!rsa_key) {
+ return -1;
+ }
+
+ nettle_mpz_init_set_str_256_u(rsa->pub.n, rsa_key->n.len, rsa_key->n.data);
+ nettle_mpz_init_set_str_256_u(rsa->pub.e, rsa_key->e.len, rsa_key->e.data);
+ nettle_mpz_init_set_str_256_u(rsa->priv.d, rsa_key->d.len, rsa_key->d.data);
+ nettle_mpz_init_set_str_256_u(rsa->priv.p, rsa_key->p.len, rsa_key->p.data);
+ nettle_mpz_init_set_str_256_u(rsa->priv.q, rsa_key->q.len, rsa_key->q.data);
+ nettle_mpz_init_set_str_256_u(rsa->priv.a, rsa_key->dp.len,
+ rsa_key->dp.data);
+ nettle_mpz_init_set_str_256_u(rsa->priv.b, rsa_key->dq.len,
+ rsa_key->dq.data);
+ nettle_mpz_init_set_str_256_u(rsa->priv.c, rsa_key->u.len, rsa_key->u.data);
+
+ if (!rsa_public_key_prepare(&rsa->pub)) {
+ error_setg(errp, "Failed to check RSA key");
+ return -1;
+ }
+
+ /**
+ * Since in the kernel's unit test, the p, q, a, b, c of some
+ * private keys is 0, only the simplest length check is done here
+ */
+ if (rsa_key->p.len > 1 &&
+ rsa_key->q.len > 1 &&
+ rsa_key->dp.len > 1 &&
+ rsa_key->dq.len > 1 &&
+ rsa_key->u.len > 1) {
+ if (!rsa_private_key_prepare(&rsa->priv)) {
+ error_setg(errp, "Failed to check RSA key");
+ return -1;
+ }
+ } else {
+ rsa->priv.size = rsa->pub.size;
+ }
+ qcrypto_nettle_rsa_set_akcipher_size(
+ (QCryptoAkCipher *)rsa, rsa->priv.size);
+
+ return 0;
+}
+
+static int qcrypt_nettle_parse_rsa_public_key(QCryptoNettleRSA *rsa,
+ const uint8_t *key,
+ size_t keylen,
+ Error **errp)
+{
+ g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
+ QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp);
+
+ if (!rsa_key) {
+ return -1;
+ }
+ nettle_mpz_init_set_str_256_u(rsa->pub.n, rsa_key->n.len, rsa_key->n.data);
+ nettle_mpz_init_set_str_256_u(rsa->pub.e, rsa_key->e.len, rsa_key->e.data);
+
+ if (!rsa_public_key_prepare(&rsa->pub)) {
+ error_setg(errp, "Failed to check RSA key");
+ return -1;
+ }
+ qcrypto_nettle_rsa_set_akcipher_size(
+ (QCryptoAkCipher *)rsa, rsa->pub.size);
+
+ return 0;
+}
+
+static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
+{
+ qcrypto_random_bytes(out, len, &error_abort);
+}
+
+static int qcrypto_nettle_rsa_encrypt(QCryptoAkCipher *akcipher,
+ const void *data, size_t data_len,
+ void *enc, size_t enc_len,
+ Error **errp)
+{
+
+ QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher;
+ mpz_t c;
+ int ret = -1;
+
+ if (data_len > rsa->pub.size) {
+ error_setg(errp, "Plaintext length should be less than key size: %lu",
+ rsa->pub.size);
+ return ret;
+ }
+
+ if (enc_len < rsa->pub.size) {
+ error_setg(errp, "Ciphertext buffer length cannot less than "
+ "key size: %lu", rsa->pub.size);
+ return ret;
+ }
+
+ /* Nettle do not support RSA encryption without any padding */
+ switch (rsa->padding_alg) {
+ case QCRYPTO_RSA_PADDING_ALG_RAW:
+ error_setg(errp, "RSA with raw padding is not supported");
+ break;
+
+ case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+ mpz_init(c);
+ if (rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
+ data_len, (uint8_t *)data, c) != 1) {
+ error_setg(errp, "Failed to encrypt");
+ } else {
+ nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
+ ret = nettle_mpz_sizeinbase_256_u(c);
+ }
+ mpz_clear(c);
+ break;
+
+ default:
+ error_setg(errp, "Unknown padding");
+ }
+
+ return ret;
+}
+
+static int qcrypto_nettle_rsa_decrypt(QCryptoAkCipher *akcipher,
+ const void *enc, size_t enc_len,
+ void *data, size_t data_len,
+ Error **errp)
+{
+ QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher;
+ mpz_t c;
+ int ret = -1;
+
+ if (enc_len > rsa->priv.size) {
+ error_setg(errp, "Ciphertext length is greater than key size: %lu",
+ rsa->priv.size);
+ return ret;
+ }
+
+ switch (rsa->padding_alg) {
+ case QCRYPTO_RSA_PADDING_ALG_RAW:
+ error_setg(errp, "RSA with raw padding is not supported");
+ break;
+
+ case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+ nettle_mpz_init_set_str_256_u(c, enc_len, enc);
+ if (!rsa_decrypt(&rsa->priv, &data_len, (uint8_t *)data, c)) {
+ error_setg(errp, "Failed to decrypt");
+ } else {
+ ret = data_len;
+ }
+
+ mpz_clear(c);
+ break;
+
+ default:
+ error_setg(errp, "Unknown padding algorithm: %d", rsa->padding_alg);
+ }
+
+ return ret;
+}
+
+static int qcrypto_nettle_rsa_sign(QCryptoAkCipher *akcipher,
+ const void *data, size_t data_len,
+ void *sig, size_t sig_len, Error **errp)
+{
+ QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher;
+ int ret = -1, rv;
+ mpz_t s;
+
+ /**
+ * The RSA algorithm cannot be used for signature/verification
+ * without padding.
+ */
+ if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
+ error_setg(errp, "Try to make signature without padding");
+ return ret;
+ }
+
+ if (data_len > rsa->priv.size) {
+ error_setg(errp, "Data length is greater than key size: %lu",
+ rsa->priv.size);
+ return ret;
+ }
+
+ if (sig_len < rsa->priv.size) {
+ error_setg(errp, "Signature buffer length cannot less than "
+ "key size: %lu", rsa->priv.size);
+ return ret;
+ }
+
+ mpz_init(s);
+ switch (rsa->hash_alg) {
+ case QCRYPTO_HASH_ALG_MD5:
+ rv = rsa_md5_sign_digest(&rsa->priv, data, s);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA1:
+ rv = rsa_sha1_sign_digest(&rsa->priv, data, s);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA256:
+ rv = rsa_sha256_sign_digest(&rsa->priv, data, s);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA512:
+ rv = rsa_sha512_sign_digest(&rsa->priv, data, s);
+ break;
+
+ default:
+ error_setg(errp, "Unknown hash algorithm: %d", rsa->hash_alg);
+ goto cleanup;
+ }
+
+ if (rv != 1) {
+ error_setg(errp, "Failed to make signature");
+ goto cleanup;
+ }
+ nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
+ ret = nettle_mpz_sizeinbase_256_u(s);
+
+cleanup:
+ mpz_clear(s);
+
+ return ret;
+}
+
+static int qcrypto_nettle_rsa_verify(QCryptoAkCipher *akcipher,
+ const void *sig, size_t sig_len,
+ const void *data, size_t data_len,
+ Error **errp)
+{
+ QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher;
+
+ int ret = -1, rv;
+ mpz_t s;
+
+ /**
+ * The RSA algorithm cannot be used for signature/verification
+ * without padding.
+ */
+ if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
+ error_setg(errp, "Try to verify signature without padding");
+ return ret;
+ }
+ if (data_len > rsa->pub.size) {
+ error_setg(errp, "Data length is greater than key size: %lu",
+ rsa->pub.size);
+ return ret;
+ }
+ if (sig_len < rsa->pub.size) {
+ error_setg(errp, "Signature length is greater than key size: %lu",
+ rsa->pub.size);
+ return ret;
+ }
+
+ nettle_mpz_init_set_str_256_u(s, sig_len, sig);
+ switch (rsa->hash_alg) {
+ case QCRYPTO_HASH_ALG_MD5:
+ rv = rsa_md5_verify_digest(&rsa->pub, data, s);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA1:
+ rv = rsa_sha1_verify_digest(&rsa->pub, data, s);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA256:
+ rv = rsa_sha256_verify_digest(&rsa->pub, data, s);
+ break;
+
+ case QCRYPTO_HASH_ALG_SHA512:
+ rv = rsa_sha512_verify_digest(&rsa->pub, data, s);
+ break;
+
+ default:
+ error_setg(errp, "Unsupported hash algorithm: %d", rsa->hash_alg);
+ goto cleanup;
+ }
+
+ if (rv != 1) {
+ error_setg(errp, "Failed to verify signature");
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ mpz_clear(s);
+
+ return ret;
+}
+
+QCryptoAkCipherDriver nettle_rsa = {
+ .encrypt = qcrypto_nettle_rsa_encrypt,
+ .decrypt = qcrypto_nettle_rsa_decrypt,
+ .sign = qcrypto_nettle_rsa_sign,
+ .verify = qcrypto_nettle_rsa_verify,
+ .free = qcrypto_nettle_rsa_free,
+};
+
+static QCryptoAkCipher *qcrypto_nettle_rsa_new(
+ const QCryptoAkCipherOptionsRSA *opt,
+ QCryptoAkCipherKeyType type,
+ const uint8_t *key, size_t keylen,
+ Error **errp)
+{
+ QCryptoNettleRSA *rsa = g_new0(QCryptoNettleRSA, 1);
+
+ rsa->padding_alg = opt->padding_alg;
+ rsa->hash_alg = opt->hash_alg;
+ rsa->akcipher.driver = &nettle_rsa;
+ rsa_public_key_init(&rsa->pub);
+ rsa_private_key_init(&rsa->priv);
+
+ switch (type) {
+ case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ if (qcrypt_nettle_parse_rsa_private_key(rsa, key, keylen, errp) != 0) {
+ goto error;
+ }
+ break;
+
+ case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ if (qcrypt_nettle_parse_rsa_public_key(rsa, key, keylen, errp) != 0) {
+ goto error;
+ }
+ break;
+
+ default:
+ error_setg(errp, "Unknown akcipher key type %d", type);
+ goto error;
+ }
+
+ return (QCryptoAkCipher *)rsa;
+
+error:
+ qcrypto_nettle_rsa_free((QCryptoAkCipher *)rsa);
+ return NULL;
+}
+
+
+bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts)
+{
+ switch (opts->alg) {
+ case QCRYPTO_AKCIPHER_ALG_RSA:
+ switch (opts->u.rsa.padding_alg) {
+ case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+ switch (opts->u.rsa.hash_alg) {
+ case QCRYPTO_HASH_ALG_MD5:
+ case QCRYPTO_HASH_ALG_SHA1:
+ case QCRYPTO_HASH_ALG_SHA256:
+ case QCRYPTO_HASH_ALG_SHA512:
+ return true;
+
+ default:
+ return false;
+ }
+
+ case QCRYPTO_RSA_PADDING_ALG_RAW:
+ default:
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+}
diff --git a/crypto/akcipher.c b/crypto/akcipher.c
index ab28bf415b..f287083f92 100644
--- a/crypto/akcipher.c
+++ b/crypto/akcipher.c
@@ -23,6 +23,9 @@
#include "crypto/akcipher.h"
#include "akcipherpriv.h"

+#if defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED)
+#include "akcipher-nettle.c.inc"
+#else
QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
QCryptoAkCipherKeyType type,
const uint8_t *key, size_t keylen,
@@ -37,6 +40,7 @@ bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts)
{
return false;
}
+#endif

int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher,
const void *in, size_t in_len,
diff --git a/crypto/meson.build b/crypto/meson.build
index b8152ae7cb..5f03a30d34 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -21,10 +21,14 @@ crypto_ss.add(files(
'tlscredspsk.c',
'tlscredsx509.c',
'tlssession.c',
+ 'rsakey.c',
))

if nettle.found()
crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c'))
+ if hogweed.found()
+ crypto_ss.add(gmp, hogweed)
+ endif
if xts == 'private'
crypto_ss.add(files('xts.c'))
endif
diff --git a/crypto/rsakey-builtin.c.inc b/crypto/rsakey-builtin.c.inc
new file mode 100644
index 0000000000..aeeacc8f9b
--- /dev/null
+++ b/crypto/rsakey-builtin.c.inc
@@ -0,0 +1,200 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "der.h"
+#include "rsakey.h"
+
+static int extract_mpi(void *ctx, const uint8_t *value,
+ size_t vlen, Error **errp)
+{
+ QCryptoAkCipherMPI *mpi = (QCryptoAkCipherMPI *)ctx;
+ if (vlen == 0) {
+ error_setg(errp, "Empty mpi field");
+ return -1;
+ }
+ mpi->data = g_memdup2(value, vlen);
+ mpi->len = vlen;
+ return 0;
+}
+
+static int extract_version(void *ctx, const uint8_t *value,
+ size_t vlen, Error **errp)
+{
+ uint8_t *version = (uint8_t *)ctx;
+ if (vlen != 1 || *value > 1) {
+ error_setg(errp, "Invalid rsakey version");
+ return -1;
+ }
+ *version = *value;
+ return 0;
+}
+
+static int extract_seq_content(void *ctx, const uint8_t *value,
+ size_t vlen, Error **errp)
+{
+ const uint8_t **content = (const uint8_t **)ctx;
+ if (vlen == 0) {
+ error_setg(errp, "Empty sequence");
+ return -1;
+ }
+ *content = value;
+ return 0;
+}
+
+/**
+ *
+ * RsaPubKey ::= SEQUENCE {
+ * n INTEGER
+ * e INTEGER
+ * }
+ */
+static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_public_key_parse(
+ const uint8_t *key, size_t keylen, Error **errp)
+{
+ QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1);
+ const uint8_t *seq;
+ size_t seq_length;
+ int decode_ret;
+
+ decode_ret = qcrypto_der_decode_seq(&key, &keylen,
+ extract_seq_content, &seq, errp);
+ if (decode_ret < 0 || keylen != 0) {
+ goto error;
+ }
+ seq_length = decode_ret;
+
+ if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi,
+ &rsa->n, errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi,
+ &rsa->e, errp) < 0) {
+ goto error;
+ }
+ if (seq_length != 0) {
+ goto error;
+ }
+
+ return rsa;
+
+error:
+ if (errp && !*errp) {
+ error_setg(errp, "Invalid RSA public key");
+ }
+ qcrypto_akcipher_rsakey_free(rsa);
+ return NULL;
+}
+
+/**
+ * RsaPrivKey ::= SEQUENCE {
+ * version INTEGER
+ * n INTEGER
+ * e INTEGER
+ * d INTEGER
+ * p INTEGER
+ * q INTEGER
+ * dp INTEGER
+ * dq INTEGER
+ * u INTEGER
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ */
+static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_private_key_parse(
+ const uint8_t *key, size_t keylen, Error **errp)
+{
+ QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1);
+ uint8_t version;
+ const uint8_t *seq;
+ int decode_ret;
+ size_t seq_length;
+
+ decode_ret = qcrypto_der_decode_seq(&key, &keylen, extract_seq_content,
+ &seq, errp);
+ if (decode_ret < 0 || keylen != 0) {
+ goto error;
+ }
+ seq_length = decode_ret;
+
+ decode_ret = qcrypto_der_decode_int(&seq, &seq_length, extract_version,
+ &version, errp);
+
+ if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi,
+ &rsa->n, errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi,
+ &rsa->e, errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi,
+ &rsa->d, errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->p,
+ errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->q,
+ errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dp,
+ errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dq,
+ errp) < 0 ||
+ qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->u,
+ errp) < 0) {
+ goto error;
+ }
+
+ /**
+ * According to the standard, otherPrimeInfos must be present for version 1.
+ * There is no strict verification here, this is to be compatible with
+ * the unit test of the kernel. TODO: remove this until linux kernel's
+ * unit-test is fixed.
+ */
+ if (version == 1 && seq_length != 0) {
+ if (qcrypto_der_decode_seq(&seq, &seq_length, NULL, NULL, errp) < 0) {
+ goto error;
+ }
+ if (seq_length != 0) {
+ goto error;
+ }
+ return rsa;
+ }
+ if (seq_length != 0) {
+ goto error;
+ }
+
+ return rsa;
+
+error:
+ if (errp && !*errp) {
+ error_setg(errp, "Invalid RSA private key");
+ }
+ qcrypto_akcipher_rsakey_free(rsa);
+ return NULL;
+}
+
+QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse(
+ QCryptoAkCipherKeyType type, const uint8_t *key,
+ size_t keylen, Error **errp)
+{
+ switch (type) {
+ case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ return qcrypto_builtin_rsa_private_key_parse(key, keylen, errp);
+
+ case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ return qcrypto_builtin_rsa_public_key_parse(key, keylen, errp);
+
+ default:
+ error_setg(errp, "Unknown key type: %d", type);
+ return NULL;
+ }
+}
diff --git a/crypto/rsakey-nettle.c.inc b/crypto/rsakey-nettle.c.inc
new file mode 100644
index 0000000000..cc49872e78
--- /dev/null
+++ b/crypto/rsakey-nettle.c.inc
@@ -0,0 +1,158 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <nettle/asn1.h>
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "rsakey.h"
+
+static bool DumpMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi)
+{
+ mpi->data = g_memdup2(i->data, i->length);
+ mpi->len = i->length;
+ return true;
+}
+
+static bool GetMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi)
+{
+ if (asn1_der_iterator_next(i) != ASN1_ITERATOR_PRIMITIVE ||
+ i->type != ASN1_INTEGER) {
+ return false;
+ }
+ return DumpMPI(i, mpi);
+}
+
+/**
+ * RsaPrivKey ::= SEQUENCE {
+ * version INTEGER
+ * n INTEGER
+ * e INTEGER
+ * d INTEGER
+ * p INTEGER
+ * q INTEGER
+ * dp INTEGER
+ * dq INTEGER
+ * u INTEGER
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ */
+static QCryptoAkCipherRSAKey *qcrypto_nettle_rsa_private_key_parse(
+ const uint8_t *key, size_t keylen, Error **errp)
+{
+ QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1);
+ struct asn1_der_iterator i;
+ uint32_t version;
+ int tag;
+
+ /* Parse entire struct */
+ if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED ||
+ i.type != ASN1_SEQUENCE ||
+ asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE ||
+ i.type != ASN1_INTEGER ||
+ !asn1_der_get_uint32(&i, &version) ||
+ version > 1 ||
+ !GetMPI(&i, &rsa->n) ||
+ !GetMPI(&i, &rsa->e) ||
+ !GetMPI(&i, &rsa->d) ||
+ !GetMPI(&i, &rsa->p) ||
+ !GetMPI(&i, &rsa->q) ||
+ !GetMPI(&i, &rsa->dp) ||
+ !GetMPI(&i, &rsa->dq) ||
+ !GetMPI(&i, &rsa->u)) {
+ goto error;
+ }
+
+ if (version == 1) {
+ tag = asn1_der_iterator_next(&i);
+ /**
+ * According to the standard otherPrimeInfos must be present for
+ * version 1. There is no strict verification here, this is to be
+ * compatible with the unit test of the kernel. TODO: remove this
+ * until linux-kernel's unit-test is fixed;
+ */
+ if (tag == ASN1_ITERATOR_END) {
+ return rsa;
+ }
+ if (tag != ASN1_ITERATOR_CONSTRUCTED ||
+ i.type != ASN1_SEQUENCE) {
+ goto error;
+ }
+ }
+
+ if (asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) {
+ goto error;
+ }
+
+ return rsa;
+
+error:
+ error_setg(errp, "Failed to parse RSA private key");
+ qcrypto_akcipher_rsakey_free(rsa);
+ return NULL;
+}
+
+/**
+ * RsaPubKey ::= SEQUENCE {
+ * n INTEGER
+ * e INTEGER
+ * }
+ */
+static QCryptoAkCipherRSAKey *qcrypto_nettle_rsa_public_key_parse(
+ const uint8_t *key, size_t keylen, Error **errp)
+{
+
+ QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1);
+ struct asn1_der_iterator i;
+
+ if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED ||
+ i.type != ASN1_SEQUENCE ||
+ asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE ||
+ !DumpMPI(&i, &rsa->n) ||
+ !GetMPI(&i, &rsa->e) ||
+ asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) {
+ goto error;
+ }
+
+ return rsa;
+
+error:
+ error_setg(errp, "Failed to parse RSA public key");
+ qcrypto_akcipher_rsakey_free(rsa);
+ return NULL;
+}
+
+QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse(
+ QCryptoAkCipherKeyType type, const uint8_t *key,
+ size_t keylen, Error **errp)
+{
+ switch (type) {
+ case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ return qcrypto_nettle_rsa_private_key_parse(key, keylen, errp);
+
+ case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ return qcrypto_nettle_rsa_public_key_parse(key, keylen, errp);
+
+ default:
+ error_setg(errp, "Unknown key type: %d", type);
+ return NULL;
+ }
+}
diff --git a/crypto/rsakey.c b/crypto/rsakey.c
new file mode 100644
index 0000000000..cc40e072f0
--- /dev/null
+++ b/crypto/rsakey.c
@@ -0,0 +1,44 @@
+/*
+ * QEMU Crypto RSA key parser
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "rsakey.h"
+
+void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *rsa_key)
+{
+ if (!rsa_key) {
+ return;
+ }
+ g_free(rsa_key->n.data);
+ g_free(rsa_key->e.data);
+ g_free(rsa_key->d.data);
+ g_free(rsa_key->p.data);
+ g_free(rsa_key->q.data);
+ g_free(rsa_key->dp.data);
+ g_free(rsa_key->dq.data);
+ g_free(rsa_key->u.data);
+ g_free(rsa_key);
+}
+
+#if defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED)
+#include "rsakey-nettle.c.inc"
+#else
+#include "rsakey-builtin.c.inc"
+#endif
diff --git a/crypto/rsakey.h b/crypto/rsakey.h
new file mode 100644
index 0000000000..17bb22333d
--- /dev/null
+++ b/crypto/rsakey.h
@@ -0,0 +1,94 @@
+/*
+ * QEMU Crypto RSA key parser
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_RSAKEY_H
+#define QCRYPTO_RSAKEY_H
+
+#include <nettle/bignum.h>
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "crypto/akcipher.h"
+
+typedef struct QCryptoAkCipherRSAKey QCryptoAkCipherRSAKey;
+typedef struct QCryptoAkCipherMPI QCryptoAkCipherMPI;
+
+/**
+ * Multiple precious integer, encoded as two' complement,
+ * copied directly from DER encoded ASN.1 structures.
+ */
+struct QCryptoAkCipherMPI {
+ uint8_t *data;
+ size_t len;
+};
+
+/* See rfc2437: https://datatracker.ietf.org/doc/html/rfc2437 */
+struct QCryptoAkCipherRSAKey {
+ /* The modulus */
+ QCryptoAkCipherMPI n;
+ /* The public exponent */
+ QCryptoAkCipherMPI e;
+ /* The private exponent */
+ QCryptoAkCipherMPI d;
+ /* The first factor */
+ QCryptoAkCipherMPI p;
+ /* The second factor */
+ QCryptoAkCipherMPI q;
+ /* The first factor's exponent */
+ QCryptoAkCipherMPI dp;
+ /* The second factor's exponent */
+ QCryptoAkCipherMPI dq;
+ /* The CRT coefficient */
+ QCryptoAkCipherMPI u;
+};
+
+/**
+ * Parse DER encoded ASN.1 RSA keys, expected ASN.1 schemas:
+ * RsaPrivKey ::= SEQUENCE {
+ * version INTEGER
+ * n INTEGER
+ * e INTEGER
+ * d INTEGER
+ * p INTEGER
+ * q INTEGER
+ * dp INTEGER
+ * dq INTEGER
+ * u INTEGER
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ *
+ * RsaPubKey ::= SEQUENCE {
+ * n INTEGER
+ * e INTEGER
+ * }
+ *
+ * Returns: On success QCryptoAkCipherRSAKey is returned, otherwise returns NULL
+ */
+QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse(
+ QCryptoAkCipherKeyType type,
+ const uint8_t *key, size_t keylen, Error **errp);
+
+void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *key);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipherRSAKey,
+ qcrypto_akcipher_rsakey_free);
+
+#endif
diff --git a/meson.build b/meson.build
index 40132b4804..68bd083189 100644
--- a/meson.build
+++ b/meson.build
@@ -1098,6 +1098,7 @@ endif
# gcrypt over nettle for performance reasons.
gcrypt = not_found
nettle = not_found
+hogweed = not_found
xts = 'none'

if get_option('nettle').enabled() and get_option('gcrypt').enabled()
@@ -1135,6 +1136,15 @@ if not gnutls_crypto.found()
endif
endif

+gmp = dependency('gmp', required: false, method: 'pkg-config', kwargs: static_kwargs)
+if nettle.found() and gmp.found()
+ hogweed = dependency('hogweed', version: '>=3.4',
+ method: 'pkg-config',
+ required: get_option('nettle'),
+ kwargs: static_kwargs)
+endif
+
+
gtk = not_found
gtkx11 = not_found
vte = not_found
@@ -1744,6 +1754,7 @@ config_host_data.set('CONFIG_GNUTLS', gnutls.found())
config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
config_host_data.set('CONFIG_NETTLE', nettle.found())
+config_host_data.set('CONFIG_HOGWEED', hogweed.found())
config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
config_host_data.set('CONFIG_STATX', has_statx)
--
2.20.1


2022-05-23 09:49:44

by Daniel P. Berrangé

[permalink] [raw]
Subject: Re: [PATCH v6 5/9] crypto: Implement RSA algorithm by hogweed

On Sat, May 14, 2022 at 08:55:00AM +0800, zhenwei pi wrote:
> From: Lei He <[email protected]>
>
> Implement RSA algorithm by hogweed from nettle. Thus QEMU supports
> a 'real' RSA backend to handle request from guest side. It's
> important to test RSA offload case without OS & hardware requirement.
>
> Signed-off-by: lei he <[email protected]>
> Signed-off-by: zhenwei pi <[email protected]>
> ---
> crypto/akcipher-nettle.c.inc | 451 +++++++++++++++++++++++++++++++++++
> crypto/akcipher.c | 4 +
> crypto/meson.build | 4 +
> crypto/rsakey-builtin.c.inc | 200 ++++++++++++++++
> crypto/rsakey-nettle.c.inc | 158 ++++++++++++
> crypto/rsakey.c | 44 ++++
> crypto/rsakey.h | 94 ++++++++
> meson.build | 11 +
> 8 files changed, 966 insertions(+)
> create mode 100644 crypto/akcipher-nettle.c.inc
> create mode 100644 crypto/rsakey-builtin.c.inc
> create mode 100644 crypto/rsakey-nettle.c.inc
> create mode 100644 crypto/rsakey.c
> create mode 100644 crypto/rsakey.h
>
> diff --git a/crypto/akcipher-nettle.c.inc b/crypto/akcipher-nettle.c.inc
> new file mode 100644
> index 0000000000..0796bddcaa
> --- /dev/null
> +++ b/crypto/akcipher-nettle.c.inc

> +static int qcrypto_nettle_rsa_encrypt(QCryptoAkCipher *akcipher,
> + const void *data, size_t data_len,
> + void *enc, size_t enc_len,
> + Error **errp)
> +{
> +
> + QCryptoNettleRSA *rsa = (QCryptoNettleRSA *)akcipher;
> + mpz_t c;
> + int ret = -1;
> +
> + if (data_len > rsa->pub.size) {
> + error_setg(errp, "Plaintext length should be less than key size: %lu",
> + rsa->pub.size);
> + return ret;
> + }

This needs to include both the good & bad values. I'm going to make
the following changes to error messages:

ie

+ error_setg(errp, "Plaintext length %zu is greater than key size: %lu"
+ data_len, rsa->pub.size);
return ret;
}


But also the '%lu' needs to change to '%zu' because the rsa->pub.size
parameter is 'size_t'. %lu doesn't match size_t on 32-bit hosts.

The same issues appear in several other error messages through this
file

With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|


2022-05-23 09:49:52

by Daniel P. Berrangé

[permalink] [raw]
Subject: Re: [PATCH v6 5/9] crypto: Implement RSA algorithm by hogweed

On Sat, May 14, 2022 at 08:55:00AM +0800, zhenwei pi wrote:
> From: Lei He <[email protected]>
>
> Implement RSA algorithm by hogweed from nettle. Thus QEMU supports
> a 'real' RSA backend to handle request from guest side. It's
> important to test RSA offload case without OS & hardware requirement.
>
> Signed-off-by: lei he <[email protected]>
> Signed-off-by: zhenwei pi <[email protected]>
> ---
> crypto/akcipher-nettle.c.inc | 451 +++++++++++++++++++++++++++++++++++
> crypto/akcipher.c | 4 +
> crypto/meson.build | 4 +
> crypto/rsakey-builtin.c.inc | 200 ++++++++++++++++
> crypto/rsakey-nettle.c.inc | 158 ++++++++++++
> crypto/rsakey.c | 44 ++++
> crypto/rsakey.h | 94 ++++++++
> meson.build | 11 +
> 8 files changed, 966 insertions(+)
> create mode 100644 crypto/akcipher-nettle.c.inc
> create mode 100644 crypto/rsakey-builtin.c.inc
> create mode 100644 crypto/rsakey-nettle.c.inc
> create mode 100644 crypto/rsakey.c
> create mode 100644 crypto/rsakey.h


> diff --git a/crypto/rsakey.h b/crypto/rsakey.h
> new file mode 100644
> index 0000000000..17bb22333d
> --- /dev/null
> +++ b/crypto/rsakey.h
> @@ -0,0 +1,94 @@
> +
> +#ifndef QCRYPTO_RSAKEY_H
> +#define QCRYPTO_RSAKEY_H
> +
> +#include <nettle/bignum.h>

This should be removed -it isn't needed and breaks build on
without-nettle build configurations.

With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|


2022-05-23 09:49:54

by Daniel P. Berrangé

[permalink] [raw]
Subject: Re: [PATCH v6 7/9] test/crypto: Add test suite for crypto akcipher

On Sat, May 14, 2022 at 08:55:02AM +0800, zhenwei pi wrote:
> From: Lei He <[email protected]>
>
> Add unit test and benchmark test for crypto akcipher.
>
> Signed-off-by: lei he <[email protected]>
> Signed-off-by: zhenwei pi <[email protected]>
> Reviewed-by: Daniel P. Berrangé <[email protected]>
> ---
> tests/bench/benchmark-crypto-akcipher.c | 157 ++++++
> tests/bench/meson.build | 1 +
> tests/bench/test_akcipher_keys.inc | 537 ++++++++++++++++++
> tests/unit/meson.build | 1 +
> tests/unit/test-crypto-akcipher.c | 711 ++++++++++++++++++++++++
> 5 files changed, 1407 insertions(+)
> create mode 100644 tests/bench/benchmark-crypto-akcipher.c
> create mode 100644 tests/bench/test_akcipher_keys.inc
> create mode 100644 tests/unit/test-crypto-akcipher.c
>
> diff --git a/tests/bench/benchmark-crypto-akcipher.c b/tests/bench/benchmark-crypto-akcipher.c
> new file mode 100644
> index 0000000000..c6c80c0be1
> --- /dev/null
> +++ b/tests/bench/benchmark-crypto-akcipher.c
> @@ -0,0 +1,157 @@
> +/*
> + * QEMU Crypto akcipher speed benchmark
> + *
> + * Copyright (c) 2022 Bytedance
> + *
> + * Authors:
> + * lei he <[email protected]>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> + * (at your option) any later version. See the COPYING file in the
> + * top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "crypto/init.h"
> +#include "crypto/akcipher.h"
> +#include "standard-headers/linux/virtio_crypto.h"
> +
> +#include "test_akcipher_keys.inc"
> +
> +static bool keep_running;
> +
> +static void alarm_handler(int sig)
> +{
> + keep_running = false;
> +}
> +
> +static QCryptoAkCipher *create_rsa_akcipher(const uint8_t *priv_key,
> + size_t keylen,
> + QCryptoRSAPaddingAlgorithm padding,
> + QCryptoHashAlgorithm hash)
> +{
> + QCryptoAkCipherOptions opt;
> + QCryptoAkCipher *rsa;
> +
> + opt.alg = QCRYPTO_AKCIPHER_ALG_RSA;
> + opt.u.rsa.padding_alg = padding;
> + opt.u.rsa.hash_alg = hash;
> + rsa = qcrypto_akcipher_new(&opt, QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
> + priv_key, keylen, &error_abort);
> + return rsa;
> +}
> +
> +static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
> + size_t key_size)
> +{
> +#define BYTE 8
> +#define SHA1_DGST_LEN 20
> +#define DURATION_SECONDS 10
> +#define PADDING QCRYPTO_RSA_PADDING_ALG_PKCS1
> +#define HASH QCRYPTO_HASH_ALG_SHA1
> +
> + g_autoptr(QCryptoAkCipher) rsa =
> + create_rsa_akcipher(priv_key, keylen, PADDING, HASH);
> + g_autofree uint8_t *dgst = NULL;
> + g_autofree uint8_t *signature = NULL;
> + size_t count;
> +
> + dgst = g_new0(uint8_t, SHA1_DGST_LEN);
> + memset(dgst, g_test_rand_int(), SHA1_DGST_LEN);
> + signature = g_new0(uint8_t, key_size / BYTE);
> +
> + g_test_message("benchmark rsa%lu (%s-%s) sign in %d seconds", key_size,
> + QCryptoRSAPaddingAlgorithm_str(PADDING),
> + QCryptoHashAlgorithm_str(HASH),
> + DURATION_SECONDS);

Needs to be '%zu' here and several other places in this file for any
parameter which is 'size_t'.

> + alarm(DURATION_SECONDS);
> + g_test_timer_start();
> + for (keep_running = true, count = 0; keep_running; ++count) {
> + g_assert(qcrypto_akcipher_sign(rsa, dgst, SHA1_DGST_LEN,
> + signature, key_size / BYTE,
> + &error_abort) > 0);
> + }
> + g_test_timer_elapsed();
> + g_test_message("rsa%lu (%s-%s) sign %lu times in %.2f seconds,"
> + " %.2f times/sec ",
> + key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
> + QCryptoHashAlgorithm_str(HASH),
> + count, g_test_timer_last(),
> + (double)count / g_test_timer_last());
> +
> + g_test_message("benchmark rsa%lu (%s-%s) verify in %d seconds", key_size,
> + QCryptoRSAPaddingAlgorithm_str(PADDING),
> + QCryptoHashAlgorithm_str(HASH),
> + DURATION_SECONDS);
> + alarm(DURATION_SECONDS);
> + g_test_timer_start();
> + for (keep_running = true, count = 0; keep_running; ++count) {
> + g_assert(qcrypto_akcipher_verify(rsa, signature, key_size / BYTE,
> + dgst, SHA1_DGST_LEN,
> + &error_abort) == 0);
> + }
> + g_test_timer_elapsed();
> + g_test_message("rsa%lu (%s-%s) verify %lu times in %.2f seconds,"
> + " %.2f times/sec ",
> + key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
> + QCryptoHashAlgorithm_str(HASH),
> + count, g_test_timer_last(),
> + (double)count / g_test_timer_last());
> +}
> +
> +static void test_rsa_1024_speed(const void *opaque)
> +{
> + size_t key_size = (size_t)opaque;
> + test_rsa_speed(rsa1024_priv_key, sizeof(rsa1024_priv_key), key_size);
> +}
> +
> +static void test_rsa_2048_speed(const void *opaque)
> +{
> + size_t key_size = (size_t)opaque;
> + test_rsa_speed(rsa2048_priv_key, sizeof(rsa2048_priv_key), key_size);
> +}
> +
> +static void test_rsa_4096_speed(const void *opaque)
> +{
> + size_t key_size = (size_t)opaque;
> + test_rsa_speed(rsa4096_priv_key, sizeof(rsa4096_priv_key), key_size);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + char *alg = NULL;
> + char *size = NULL;
> + g_test_init(&argc, &argv, NULL);
> + g_assert(qcrypto_init(NULL) == 0);
> + struct sigaction new_action, old_action;
> +
> + new_action.sa_handler = alarm_handler;
> +
> + /* Set up the structure to specify the new action. */
> + sigemptyset(&new_action.sa_mask);
> + new_action.sa_flags = 0;
> + sigaction(SIGALRM, NULL, &old_action);
> + g_assert(old_action.sa_handler != SIG_IGN);
> + sigaction(SIGALRM, &new_action, NULL);

sigaction doesn't exist on Windows so this fails to compile.
I'd suggest processing a constant amount of data, as the other
benchmark programs do, rather than trying to run for a constant
amount of time.

> +
> +#define ADD_TEST(asym_alg, keysize) \
> + if ((!alg || g_str_equal(alg, #asym_alg)) && \
> + (!size || g_str_equal(size, #keysize))) \
> + g_test_add_data_func( \
> + "/crypto/akcipher/" #asym_alg "-" #keysize, \
> + (void *)keysize, \
> + test_ ## asym_alg ## _ ## keysize ## _speed)
> +
> + if (argc >= 2) {
> + alg = argv[1];
> + }
> + if (argc >= 3) {
> + size = argv[2];
> + }
> +
> + ADD_TEST(rsa, 1024);
> + ADD_TEST(rsa, 2048);
> + ADD_TEST(rsa, 4096);
> +
> + return g_test_run();
> +}


With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|


2022-05-23 09:54:47

by Daniel P. Berrangé

[permalink] [raw]
Subject: Re: [PATCH v6 4/9] crypto: add ASN.1 DER decoder

On Sat, May 14, 2022 at 08:54:59AM +0800, zhenwei pi wrote:
> From: Lei He <[email protected]>
>
> Add an ANS.1 DER decoder which is used to parse asymmetric
> cipher keys
>
> Signed-off-by: zhenwei pi <[email protected]>
> Signed-off-by: lei he <[email protected]>
> ---
> crypto/der.c | 189 +++++++++++++++++++++++
> crypto/der.h | 81 ++++++++++
> crypto/meson.build | 1 +
> tests/unit/meson.build | 1 +
> tests/unit/test-crypto-der.c | 290 +++++++++++++++++++++++++++++++++++
> 5 files changed, 562 insertions(+)
> create mode 100644 crypto/der.c
> create mode 100644 crypto/der.h
> create mode 100644 tests/unit/test-crypto-der.c
>

> diff --git a/tests/unit/meson.build b/tests/unit/meson.build
> index 264f2bc0c8..a8af85128d 100644
> --- a/tests/unit/meson.build
> +++ b/tests/unit/meson.build
> @@ -47,6 +47,7 @@ tests = {
> 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'],
> 'test-qapi-util': [],
> 'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine-smp.c'],
> + 'test-crypto-der': [crypto],
> }

This needs to be moved to later in this file where the other
test-crypto-XXXX rules are, otherwise it fails to build
on a configuration --without-system --without-tools.


With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|