All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23  2:49 ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: jasowang, virtualization, qemu-devel, linux-crypto, herbert, zhenwei pi

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 (3):
  crypto-akcipher: Introduce akcipher types to qapi
  crypto: Implement RSA algorithm by hogweed
  tests/crypto: Add test suite for crypto akcipher

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

 backends/cryptodev-builtin.c                  | 319 +++++++-
 backends/cryptodev-vhost-user.c               |  34 +-
 backends/cryptodev.c                          |  32 +-
 crypto/akcipher-nettle.c                      | 523 +++++++++++++
 crypto/akcipher.c                             |  81 ++
 crypto/asn1_decoder.c                         | 185 +++++
 crypto/asn1_decoder.h                         |  42 +
 crypto/meson.build                            |   4 +
 hw/virtio/virtio-crypto.c                     | 326 ++++++--
 include/crypto/akcipher.h                     | 155 ++++
 include/hw/virtio/virtio-crypto.h             |   5 +-
 .../standard-headers/linux/virtio_crypto.h    |  82 +-
 include/sysemu/cryptodev.h                    |  88 ++-
 meson.build                                   |  11 +
 qapi/crypto.json                              |  86 +++
 tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
 tests/bench/meson.build                       |   6 +
 tests/bench/test_akcipher_keys.inc            | 277 +++++++
 tests/unit/meson.build                        |   1 +
 tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
 20 files changed, 2990 insertions(+), 145 deletions(-)
 create mode 100644 crypto/akcipher-nettle.c
 create mode 100644 crypto/akcipher.c
 create mode 100644 crypto/asn1_decoder.c
 create mode 100644 crypto/asn1_decoder.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

-- 
2.25.1


^ permalink raw reply	[flat|nested] 62+ messages in thread

* [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23  2:49 ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, qemu-devel, zhenwei pi, virtualization, linux-crypto

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 (3):
  crypto-akcipher: Introduce akcipher types to qapi
  crypto: Implement RSA algorithm by hogweed
  tests/crypto: Add test suite for crypto akcipher

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

 backends/cryptodev-builtin.c                  | 319 +++++++-
 backends/cryptodev-vhost-user.c               |  34 +-
 backends/cryptodev.c                          |  32 +-
 crypto/akcipher-nettle.c                      | 523 +++++++++++++
 crypto/akcipher.c                             |  81 ++
 crypto/asn1_decoder.c                         | 185 +++++
 crypto/asn1_decoder.h                         |  42 +
 crypto/meson.build                            |   4 +
 hw/virtio/virtio-crypto.c                     | 326 ++++++--
 include/crypto/akcipher.h                     | 155 ++++
 include/hw/virtio/virtio-crypto.h             |   5 +-
 .../standard-headers/linux/virtio_crypto.h    |  82 +-
 include/sysemu/cryptodev.h                    |  88 ++-
 meson.build                                   |  11 +
 qapi/crypto.json                              |  86 +++
 tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
 tests/bench/meson.build                       |   6 +
 tests/bench/test_akcipher_keys.inc            | 277 +++++++
 tests/unit/meson.build                        |   1 +
 tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
 20 files changed, 2990 insertions(+), 145 deletions(-)
 create mode 100644 crypto/akcipher-nettle.c
 create mode 100644 crypto/akcipher.c
 create mode 100644 crypto/asn1_decoder.c
 create mode 100644 crypto/asn1_decoder.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

-- 
2.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23  2:49 ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, jasowang, qemu-devel, zhenwei pi, virtualization, linux-crypto

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 (3):
  crypto-akcipher: Introduce akcipher types to qapi
  crypto: Implement RSA algorithm by hogweed
  tests/crypto: Add test suite for crypto akcipher

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

 backends/cryptodev-builtin.c                  | 319 +++++++-
 backends/cryptodev-vhost-user.c               |  34 +-
 backends/cryptodev.c                          |  32 +-
 crypto/akcipher-nettle.c                      | 523 +++++++++++++
 crypto/akcipher.c                             |  81 ++
 crypto/asn1_decoder.c                         | 185 +++++
 crypto/asn1_decoder.h                         |  42 +
 crypto/meson.build                            |   4 +
 hw/virtio/virtio-crypto.c                     | 326 ++++++--
 include/crypto/akcipher.h                     | 155 ++++
 include/hw/virtio/virtio-crypto.h             |   5 +-
 .../standard-headers/linux/virtio_crypto.h    |  82 +-
 include/sysemu/cryptodev.h                    |  88 ++-
 meson.build                                   |  11 +
 qapi/crypto.json                              |  86 +++
 tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
 tests/bench/meson.build                       |   6 +
 tests/bench/test_akcipher_keys.inc            | 277 +++++++
 tests/unit/meson.build                        |   1 +
 tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
 20 files changed, 2990 insertions(+), 145 deletions(-)
 create mode 100644 crypto/akcipher-nettle.c
 create mode 100644 crypto/akcipher.c
 create mode 100644 crypto/asn1_decoder.c
 create mode 100644 crypto/asn1_decoder.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

-- 
2.25.1



^ permalink raw reply	[flat|nested] 62+ messages in thread

* [PATCH v3 1/6] virtio-crypto: header update
  2022-03-23  2:49 ` zhenwei pi
  (?)
@ 2022-03-23  2:49   ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: jasowang, virtualization, qemu-devel, linux-crypto, herbert,
	zhenwei pi, lei he

Update header from linux, support akcipher service.

Reviewed-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 .../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.25.1


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 1/6] virtio-crypto: header update
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, qemu-devel, zhenwei pi, virtualization, linux-crypto, lei he

Update header from linux, support akcipher service.

Reviewed-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 .../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.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 1/6] virtio-crypto: header update
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, jasowang, qemu-devel, zhenwei pi, virtualization,
	linux-crypto, lei he

Update header from linux, support akcipher service.

Reviewed-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 .../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.25.1



^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
  2022-03-23  2:49 ` zhenwei pi
  (?)
@ 2022-03-23  2:49   ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: jasowang, virtualization, qemu-devel, linux-crypto, herbert,
	Lei He, zhenwei pi

From: Lei He <helei.sig11@bytedance.com>

Introduce akcipher types, also include RSA & ECDSA related types.

Signed-off-by: Lei He <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/qapi/crypto.json b/qapi/crypto.json
index 1ec54c15ca..d44c38e3b1 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -540,3 +540,89 @@
   'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
             '*sanity-check': 'bool',
             '*passwordid': 'str' } }
+##
+# @QCryptoAkcipherAlgorithm:
+#
+# The supported algorithms for asymmetric encryption ciphers
+#
+# @rsa: RSA algorithm
+# @ecdsa: ECDSA algorithm
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherAlgorithm',
+  'prefix': 'QCRYPTO_AKCIPHER_ALG',
+  'data': ['rsa', 'ecdsa']}
+
+##
+# @QCryptoAkcipherKeyType:
+#
+# The type of asymmetric keys.
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherKeyType',
+  'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
+  'data': ['public', 'private']}
+
+##
+# @QCryptoRsaHashAlgorithm:
+#
+# The hash algorithm for RSA pkcs1 padding algothrim
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaHashAlgorithm',
+  'prefix': 'QCRYPTO_RSA_HASH_ALG',
+  'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]}
+
+##
+# @QCryptoRsaPaddingAlgorithm:
+#
+# The padding algorithm for RSA.
+#
+# @raw: no padding used
+# @pkcs1: pkcs1#v1.5
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaPaddingAlgorithm',
+  'prefix': 'QCRYPTO_RSA_PADDING_ALG',
+  'data': ['raw', 'pkcs1']}
+
+##
+# @QCryptoCurveId:
+#
+# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoCurveId',
+  'prefix': 'QCRYPTO_CURVE_ID',
+  'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']}
+
+##
+# @QCryptoRsaOptions:
+#
+# Specific parameters for RSA algorithm.
+#
+# @hash-algo: QCryptoRsaHashAlgorithm
+# @padding-algo: QCryptoRsaPaddingAlgorithm
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoRsaOptions',
+  'data': { 'hash-algo':'QCryptoRsaHashAlgorithm',
+            'padding-algo': 'QCryptoRsaPaddingAlgorithm'}}
+
+##
+# @QCryptoEcdsaOptions:
+#
+# Specific parameter for ECDSA algorithm.
+#
+# @curve-id: QCryptoCurveId
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoEcdsaOptions',
+  'data': { 'curve-id': 'QCryptoCurveId' }}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, qemu-devel, zhenwei pi, virtualization, linux-crypto, Lei He

From: Lei He <helei.sig11@bytedance.com>

Introduce akcipher types, also include RSA & ECDSA related types.

Signed-off-by: Lei He <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/qapi/crypto.json b/qapi/crypto.json
index 1ec54c15ca..d44c38e3b1 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -540,3 +540,89 @@
   'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
             '*sanity-check': 'bool',
             '*passwordid': 'str' } }
+##
+# @QCryptoAkcipherAlgorithm:
+#
+# The supported algorithms for asymmetric encryption ciphers
+#
+# @rsa: RSA algorithm
+# @ecdsa: ECDSA algorithm
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherAlgorithm',
+  'prefix': 'QCRYPTO_AKCIPHER_ALG',
+  'data': ['rsa', 'ecdsa']}
+
+##
+# @QCryptoAkcipherKeyType:
+#
+# The type of asymmetric keys.
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherKeyType',
+  'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
+  'data': ['public', 'private']}
+
+##
+# @QCryptoRsaHashAlgorithm:
+#
+# The hash algorithm for RSA pkcs1 padding algothrim
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaHashAlgorithm',
+  'prefix': 'QCRYPTO_RSA_HASH_ALG',
+  'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]}
+
+##
+# @QCryptoRsaPaddingAlgorithm:
+#
+# The padding algorithm for RSA.
+#
+# @raw: no padding used
+# @pkcs1: pkcs1#v1.5
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaPaddingAlgorithm',
+  'prefix': 'QCRYPTO_RSA_PADDING_ALG',
+  'data': ['raw', 'pkcs1']}
+
+##
+# @QCryptoCurveId:
+#
+# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoCurveId',
+  'prefix': 'QCRYPTO_CURVE_ID',
+  'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']}
+
+##
+# @QCryptoRsaOptions:
+#
+# Specific parameters for RSA algorithm.
+#
+# @hash-algo: QCryptoRsaHashAlgorithm
+# @padding-algo: QCryptoRsaPaddingAlgorithm
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoRsaOptions',
+  'data': { 'hash-algo':'QCryptoRsaHashAlgorithm',
+            'padding-algo': 'QCryptoRsaPaddingAlgorithm'}}
+
+##
+# @QCryptoEcdsaOptions:
+#
+# Specific parameter for ECDSA algorithm.
+#
+# @curve-id: QCryptoCurveId
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoEcdsaOptions',
+  'data': { 'curve-id': 'QCryptoCurveId' }}
-- 
2.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, jasowang, qemu-devel, zhenwei pi, virtualization,
	linux-crypto, Lei He

From: Lei He <helei.sig11@bytedance.com>

Introduce akcipher types, also include RSA & ECDSA related types.

Signed-off-by: Lei He <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/qapi/crypto.json b/qapi/crypto.json
index 1ec54c15ca..d44c38e3b1 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -540,3 +540,89 @@
   'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
             '*sanity-check': 'bool',
             '*passwordid': 'str' } }
+##
+# @QCryptoAkcipherAlgorithm:
+#
+# The supported algorithms for asymmetric encryption ciphers
+#
+# @rsa: RSA algorithm
+# @ecdsa: ECDSA algorithm
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherAlgorithm',
+  'prefix': 'QCRYPTO_AKCIPHER_ALG',
+  'data': ['rsa', 'ecdsa']}
+
+##
+# @QCryptoAkcipherKeyType:
+#
+# The type of asymmetric keys.
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherKeyType',
+  'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
+  'data': ['public', 'private']}
+
+##
+# @QCryptoRsaHashAlgorithm:
+#
+# The hash algorithm for RSA pkcs1 padding algothrim
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaHashAlgorithm',
+  'prefix': 'QCRYPTO_RSA_HASH_ALG',
+  'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]}
+
+##
+# @QCryptoRsaPaddingAlgorithm:
+#
+# The padding algorithm for RSA.
+#
+# @raw: no padding used
+# @pkcs1: pkcs1#v1.5
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaPaddingAlgorithm',
+  'prefix': 'QCRYPTO_RSA_PADDING_ALG',
+  'data': ['raw', 'pkcs1']}
+
+##
+# @QCryptoCurveId:
+#
+# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoCurveId',
+  'prefix': 'QCRYPTO_CURVE_ID',
+  'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']}
+
+##
+# @QCryptoRsaOptions:
+#
+# Specific parameters for RSA algorithm.
+#
+# @hash-algo: QCryptoRsaHashAlgorithm
+# @padding-algo: QCryptoRsaPaddingAlgorithm
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoRsaOptions',
+  'data': { 'hash-algo':'QCryptoRsaHashAlgorithm',
+            'padding-algo': 'QCryptoRsaPaddingAlgorithm'}}
+
+##
+# @QCryptoEcdsaOptions:
+#
+# Specific parameter for ECDSA algorithm.
+#
+# @curve-id: QCryptoCurveId
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoEcdsaOptions',
+  'data': { 'curve-id': 'QCryptoCurveId' }}
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 3/6] crypto: Introduce akcipher crypto class
  2022-03-23  2:49 ` zhenwei pi
  (?)
@ 2022-03-23  2:49   ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: jasowang, virtualization, qemu-devel, linux-crypto, herbert,
	zhenwei pi, lei he

Support basic asymmetric operations: encrypt, decrypt, sign and
verify.

Co-developed-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 crypto/akcipher.c         |  78 +++++++++++++++++++++
 crypto/meson.build        |   1 +
 include/crypto/akcipher.h | 139 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 218 insertions(+)
 create mode 100644 crypto/akcipher.c
 create mode 100644 include/crypto/akcipher.h

diff --git a/crypto/akcipher.c b/crypto/akcipher.c
new file mode 100644
index 0000000000..1e52f2fd76
--- /dev/null
+++ b/crypto/akcipher.c
@@ -0,0 +1,78 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <pizhenwei@bytedance.com>
+ *
+ * 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 "qemu/host-utils.h"
+#include "qapi/error.h"
+#include "crypto/akcipher.h"
+
+QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
+                                      QCryptoAkcipherKeyType type,
+                                      const uint8_t *key, size_t keylen,
+                                      void *para, Error **errp)
+{
+    QCryptoAkcipher *akcipher = NULL;
+
+    return akcipher;
+}
+
+int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
+                             const void *data, size_t data_len,
+                             void *enc, size_t enc_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->encrypt(akcipher, data, data_len, enc, enc_len, errp);
+}
+
+int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
+                             const void *enc, size_t enc_len,
+                             void *data, size_t data_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->decrypt(akcipher, enc, enc_len, data, data_len, errp);
+}
+
+int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
+                          const void *data, size_t data_len,
+                          void *sig, size_t sig_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->sign(akcipher, data, data_len, sig, sig_len, errp);
+}
+
+int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
+                            const void *sig, size_t sig_len,
+                            const void *data, size_t data_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->verify(akcipher, sig, sig_len, data, data_len, errp);
+}
+
+int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->free(akcipher, errp);
+}
diff --git a/crypto/meson.build b/crypto/meson.build
index 19c44bea89..c32b57aeda 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -19,6 +19,7 @@ crypto_ss.add(files(
   'tlscredspsk.c',
   'tlscredsx509.c',
   'tlssession.c',
+  'akcipher.c',
 ))
 
 if nettle.found()
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
new file mode 100644
index 0000000000..03cc3bf46b
--- /dev/null
+++ b/include/crypto/akcipher.h
@@ -0,0 +1,139 @@
+/*
+ * QEMU Crypto asymmetric algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <pizhenwei@bytedance.com>
+ *
+ * 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 "qemu/typedefs.h"
+#include "qapi/qapi-types-crypto.h"
+
+typedef struct QCryptoAkcipher QCryptoAkcipher;
+typedef struct QCryptoAkcipherDriver QCryptoAkcipherDriver;
+
+struct QCryptoAkcipherDriver {
+    int (*encrypt)(struct QCryptoAkcipher *akcipher,
+                   const void *data, size_t data_len,
+                   void *enc, size_t enc_len, Error **errp);
+    int (*decrypt)(struct QCryptoAkcipher *akcipher,
+                   const void *enc, size_t enc_len,
+                   void *data, size_t data_len, Error **errp);
+    int (*sign)(struct QCryptoAkcipher *akcipher,
+                const void *data, size_t data_len,
+                void *sig, size_t sig_len, Error **errp);
+    int (*verify)(struct QCryptoAkcipher *akcipher,
+                  const void *sig, size_t sig_len,
+                  const void *data, size_t data_len, Error **errp);
+    int (*free)(struct QCryptoAkcipher *akcipher, Error **errp);
+};
+
+struct QCryptoAkcipher {
+    QCryptoAkcipherAlgorithm alg;
+    QCryptoAkcipherKeyType type;
+    uint8_t *key;
+    size_t keylen;
+    int max_plaintext_len;
+    int max_ciphertext_len;
+    int max_signature_len;
+    int max_dgst_len;
+    QCryptoAkcipherDriver *driver;
+};
+
+QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
+                                      QCryptoAkcipherKeyType type,
+                                      const uint8_t *key, size_t keylen,
+                                      void *para, Error **errp);
+
+/**
+ * qcrypto_akcipher_encrypt:
+ * @akcipher: akcipher used to do encryption
+ * @data: plaintext pending to be encrypted
+ * @data_len: length of the plaintext, MUST less or equal
+ * akcipher->max_plaintext_len
+ * @enc: buffer to store the ciphertext
+ * @enc_len: the length of ciphertext buffer, usually equals to
+ * akcipher->max_ciphertext_len
+ * @errp: error pointer
+ *
+ * Encrypt data and write ciphertext into enc
+ *
+ * Returns: length of ciphertext if encrypt succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
+                             const void *data, size_t data_len,
+                             void *enc, size_t enc_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_decrypt:
+ * @akcipher: akcipher used to do decryption
+ * @enc: ciphertext to be decrypted
+ * @enc_len: the length of ciphertext
+ * @data: buffer to store the plaintext
+ * @data_len: length of the plaintext buffer, usually equals to
+ * akcipher->max_plaintext_len
+ * @errp: error pointer
+ *
+ * Decrypt ciphertext and write plaintext into data
+ *
+ * Returns: length of plaintext if decrypt succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
+                             const void *enc, size_t enc_len,
+                             void *data, size_t data_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_sign:
+ * @akcipher: akcipher used to generate signature
+ * @data: data to be signed
+ * @data_len: the length of data
+ * @sig: buffer to store the signature
+ * @sig_len: length of the signature buffer, usually equals to
+ * akcipher->max_signature_len
+ * @errp: error pointer
+ *
+ * Generate signature for data using akcipher
+ *
+ * Returns: length of signature if succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
+                          const void *data, size_t data_len,
+                          void *sig, size_t sig_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_verify:
+ * @akcipher: akcipher used to do verifycation
+ * @sig: pointer to the signature
+ * @sig_len: length of the signature
+ * @data: pointer to original data
+ * @data_len: the length of data
+ * @errp: error pointer
+ *
+ * Verify the signature and the data match or not
+ *
+ * Returns: 0 for succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
+                            const void *sig, size_t sig_len,
+                            const void *data, size_t data_len, Error **errp);
+
+int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
+
+
+#endif /* QCRYPTO_AKCIPHER_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 3/6] crypto: Introduce akcipher crypto class
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, qemu-devel, zhenwei pi, virtualization, linux-crypto, lei he

Support basic asymmetric operations: encrypt, decrypt, sign and
verify.

Co-developed-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 crypto/akcipher.c         |  78 +++++++++++++++++++++
 crypto/meson.build        |   1 +
 include/crypto/akcipher.h | 139 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 218 insertions(+)
 create mode 100644 crypto/akcipher.c
 create mode 100644 include/crypto/akcipher.h

diff --git a/crypto/akcipher.c b/crypto/akcipher.c
new file mode 100644
index 0000000000..1e52f2fd76
--- /dev/null
+++ b/crypto/akcipher.c
@@ -0,0 +1,78 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <pizhenwei@bytedance.com>
+ *
+ * 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 "qemu/host-utils.h"
+#include "qapi/error.h"
+#include "crypto/akcipher.h"
+
+QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
+                                      QCryptoAkcipherKeyType type,
+                                      const uint8_t *key, size_t keylen,
+                                      void *para, Error **errp)
+{
+    QCryptoAkcipher *akcipher = NULL;
+
+    return akcipher;
+}
+
+int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
+                             const void *data, size_t data_len,
+                             void *enc, size_t enc_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->encrypt(akcipher, data, data_len, enc, enc_len, errp);
+}
+
+int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
+                             const void *enc, size_t enc_len,
+                             void *data, size_t data_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->decrypt(akcipher, enc, enc_len, data, data_len, errp);
+}
+
+int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
+                          const void *data, size_t data_len,
+                          void *sig, size_t sig_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->sign(akcipher, data, data_len, sig, sig_len, errp);
+}
+
+int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
+                            const void *sig, size_t sig_len,
+                            const void *data, size_t data_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->verify(akcipher, sig, sig_len, data, data_len, errp);
+}
+
+int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->free(akcipher, errp);
+}
diff --git a/crypto/meson.build b/crypto/meson.build
index 19c44bea89..c32b57aeda 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -19,6 +19,7 @@ crypto_ss.add(files(
   'tlscredspsk.c',
   'tlscredsx509.c',
   'tlssession.c',
+  'akcipher.c',
 ))
 
 if nettle.found()
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
new file mode 100644
index 0000000000..03cc3bf46b
--- /dev/null
+++ b/include/crypto/akcipher.h
@@ -0,0 +1,139 @@
+/*
+ * QEMU Crypto asymmetric algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <pizhenwei@bytedance.com>
+ *
+ * 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 "qemu/typedefs.h"
+#include "qapi/qapi-types-crypto.h"
+
+typedef struct QCryptoAkcipher QCryptoAkcipher;
+typedef struct QCryptoAkcipherDriver QCryptoAkcipherDriver;
+
+struct QCryptoAkcipherDriver {
+    int (*encrypt)(struct QCryptoAkcipher *akcipher,
+                   const void *data, size_t data_len,
+                   void *enc, size_t enc_len, Error **errp);
+    int (*decrypt)(struct QCryptoAkcipher *akcipher,
+                   const void *enc, size_t enc_len,
+                   void *data, size_t data_len, Error **errp);
+    int (*sign)(struct QCryptoAkcipher *akcipher,
+                const void *data, size_t data_len,
+                void *sig, size_t sig_len, Error **errp);
+    int (*verify)(struct QCryptoAkcipher *akcipher,
+                  const void *sig, size_t sig_len,
+                  const void *data, size_t data_len, Error **errp);
+    int (*free)(struct QCryptoAkcipher *akcipher, Error **errp);
+};
+
+struct QCryptoAkcipher {
+    QCryptoAkcipherAlgorithm alg;
+    QCryptoAkcipherKeyType type;
+    uint8_t *key;
+    size_t keylen;
+    int max_plaintext_len;
+    int max_ciphertext_len;
+    int max_signature_len;
+    int max_dgst_len;
+    QCryptoAkcipherDriver *driver;
+};
+
+QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
+                                      QCryptoAkcipherKeyType type,
+                                      const uint8_t *key, size_t keylen,
+                                      void *para, Error **errp);
+
+/**
+ * qcrypto_akcipher_encrypt:
+ * @akcipher: akcipher used to do encryption
+ * @data: plaintext pending to be encrypted
+ * @data_len: length of the plaintext, MUST less or equal
+ * akcipher->max_plaintext_len
+ * @enc: buffer to store the ciphertext
+ * @enc_len: the length of ciphertext buffer, usually equals to
+ * akcipher->max_ciphertext_len
+ * @errp: error pointer
+ *
+ * Encrypt data and write ciphertext into enc
+ *
+ * Returns: length of ciphertext if encrypt succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
+                             const void *data, size_t data_len,
+                             void *enc, size_t enc_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_decrypt:
+ * @akcipher: akcipher used to do decryption
+ * @enc: ciphertext to be decrypted
+ * @enc_len: the length of ciphertext
+ * @data: buffer to store the plaintext
+ * @data_len: length of the plaintext buffer, usually equals to
+ * akcipher->max_plaintext_len
+ * @errp: error pointer
+ *
+ * Decrypt ciphertext and write plaintext into data
+ *
+ * Returns: length of plaintext if decrypt succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
+                             const void *enc, size_t enc_len,
+                             void *data, size_t data_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_sign:
+ * @akcipher: akcipher used to generate signature
+ * @data: data to be signed
+ * @data_len: the length of data
+ * @sig: buffer to store the signature
+ * @sig_len: length of the signature buffer, usually equals to
+ * akcipher->max_signature_len
+ * @errp: error pointer
+ *
+ * Generate signature for data using akcipher
+ *
+ * Returns: length of signature if succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
+                          const void *data, size_t data_len,
+                          void *sig, size_t sig_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_verify:
+ * @akcipher: akcipher used to do verifycation
+ * @sig: pointer to the signature
+ * @sig_len: length of the signature
+ * @data: pointer to original data
+ * @data_len: the length of data
+ * @errp: error pointer
+ *
+ * Verify the signature and the data match or not
+ *
+ * Returns: 0 for succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
+                            const void *sig, size_t sig_len,
+                            const void *data, size_t data_len, Error **errp);
+
+int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
+
+
+#endif /* QCRYPTO_AKCIPHER_H */
-- 
2.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 3/6] crypto: Introduce akcipher crypto class
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, jasowang, qemu-devel, zhenwei pi, virtualization,
	linux-crypto, lei he

Support basic asymmetric operations: encrypt, decrypt, sign and
verify.

Co-developed-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 crypto/akcipher.c         |  78 +++++++++++++++++++++
 crypto/meson.build        |   1 +
 include/crypto/akcipher.h | 139 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 218 insertions(+)
 create mode 100644 crypto/akcipher.c
 create mode 100644 include/crypto/akcipher.h

diff --git a/crypto/akcipher.c b/crypto/akcipher.c
new file mode 100644
index 0000000000..1e52f2fd76
--- /dev/null
+++ b/crypto/akcipher.c
@@ -0,0 +1,78 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <pizhenwei@bytedance.com>
+ *
+ * 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 "qemu/host-utils.h"
+#include "qapi/error.h"
+#include "crypto/akcipher.h"
+
+QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
+                                      QCryptoAkcipherKeyType type,
+                                      const uint8_t *key, size_t keylen,
+                                      void *para, Error **errp)
+{
+    QCryptoAkcipher *akcipher = NULL;
+
+    return akcipher;
+}
+
+int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
+                             const void *data, size_t data_len,
+                             void *enc, size_t enc_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->encrypt(akcipher, data, data_len, enc, enc_len, errp);
+}
+
+int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
+                             const void *enc, size_t enc_len,
+                             void *data, size_t data_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->decrypt(akcipher, enc, enc_len, data, data_len, errp);
+}
+
+int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
+                          const void *data, size_t data_len,
+                          void *sig, size_t sig_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->sign(akcipher, data, data_len, sig, sig_len, errp);
+}
+
+int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
+                            const void *sig, size_t sig_len,
+                            const void *data, size_t data_len, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->verify(akcipher, sig, sig_len, data, data_len, errp);
+}
+
+int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp)
+{
+    const QCryptoAkcipherDriver *drv = akcipher->driver;
+
+    return drv->free(akcipher, errp);
+}
diff --git a/crypto/meson.build b/crypto/meson.build
index 19c44bea89..c32b57aeda 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -19,6 +19,7 @@ crypto_ss.add(files(
   'tlscredspsk.c',
   'tlscredsx509.c',
   'tlssession.c',
+  'akcipher.c',
 ))
 
 if nettle.found()
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
new file mode 100644
index 0000000000..03cc3bf46b
--- /dev/null
+++ b/include/crypto/akcipher.h
@@ -0,0 +1,139 @@
+/*
+ * QEMU Crypto asymmetric algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: zhenwei pi <pizhenwei@bytedance.com>
+ *
+ * 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 "qemu/typedefs.h"
+#include "qapi/qapi-types-crypto.h"
+
+typedef struct QCryptoAkcipher QCryptoAkcipher;
+typedef struct QCryptoAkcipherDriver QCryptoAkcipherDriver;
+
+struct QCryptoAkcipherDriver {
+    int (*encrypt)(struct QCryptoAkcipher *akcipher,
+                   const void *data, size_t data_len,
+                   void *enc, size_t enc_len, Error **errp);
+    int (*decrypt)(struct QCryptoAkcipher *akcipher,
+                   const void *enc, size_t enc_len,
+                   void *data, size_t data_len, Error **errp);
+    int (*sign)(struct QCryptoAkcipher *akcipher,
+                const void *data, size_t data_len,
+                void *sig, size_t sig_len, Error **errp);
+    int (*verify)(struct QCryptoAkcipher *akcipher,
+                  const void *sig, size_t sig_len,
+                  const void *data, size_t data_len, Error **errp);
+    int (*free)(struct QCryptoAkcipher *akcipher, Error **errp);
+};
+
+struct QCryptoAkcipher {
+    QCryptoAkcipherAlgorithm alg;
+    QCryptoAkcipherKeyType type;
+    uint8_t *key;
+    size_t keylen;
+    int max_plaintext_len;
+    int max_ciphertext_len;
+    int max_signature_len;
+    int max_dgst_len;
+    QCryptoAkcipherDriver *driver;
+};
+
+QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
+                                      QCryptoAkcipherKeyType type,
+                                      const uint8_t *key, size_t keylen,
+                                      void *para, Error **errp);
+
+/**
+ * qcrypto_akcipher_encrypt:
+ * @akcipher: akcipher used to do encryption
+ * @data: plaintext pending to be encrypted
+ * @data_len: length of the plaintext, MUST less or equal
+ * akcipher->max_plaintext_len
+ * @enc: buffer to store the ciphertext
+ * @enc_len: the length of ciphertext buffer, usually equals to
+ * akcipher->max_ciphertext_len
+ * @errp: error pointer
+ *
+ * Encrypt data and write ciphertext into enc
+ *
+ * Returns: length of ciphertext if encrypt succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
+                             const void *data, size_t data_len,
+                             void *enc, size_t enc_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_decrypt:
+ * @akcipher: akcipher used to do decryption
+ * @enc: ciphertext to be decrypted
+ * @enc_len: the length of ciphertext
+ * @data: buffer to store the plaintext
+ * @data_len: length of the plaintext buffer, usually equals to
+ * akcipher->max_plaintext_len
+ * @errp: error pointer
+ *
+ * Decrypt ciphertext and write plaintext into data
+ *
+ * Returns: length of plaintext if decrypt succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
+                             const void *enc, size_t enc_len,
+                             void *data, size_t data_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_sign:
+ * @akcipher: akcipher used to generate signature
+ * @data: data to be signed
+ * @data_len: the length of data
+ * @sig: buffer to store the signature
+ * @sig_len: length of the signature buffer, usually equals to
+ * akcipher->max_signature_len
+ * @errp: error pointer
+ *
+ * Generate signature for data using akcipher
+ *
+ * Returns: length of signature if succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
+                          const void *data, size_t data_len,
+                          void *sig, size_t sig_len, Error **errp);
+
+/**
+ * qcrypto_akcipher_verify:
+ * @akcipher: akcipher used to do verifycation
+ * @sig: pointer to the signature
+ * @sig_len: length of the signature
+ * @data: pointer to original data
+ * @data_len: the length of data
+ * @errp: error pointer
+ *
+ * Verify the signature and the data match or not
+ *
+ * Returns: 0 for succeed, otherwise -1 is returned
+ */
+int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
+                            const void *sig, size_t sig_len,
+                            const void *data, size_t data_len, Error **errp);
+
+int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
+
+
+#endif /* QCRYPTO_AKCIPHER_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
  2022-03-23  2:49 ` zhenwei pi
  (?)
@ 2022-03-23  2:49   ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: jasowang, virtualization, qemu-devel, linux-crypto, herbert,
	Lei He, zhenwei pi

From: Lei He <helei.sig11@bytedance.com>

Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
 crypto/akcipher.c         |   3 +
 crypto/asn1_decoder.c     | 185 ++++++++++++++
 crypto/asn1_decoder.h     |  42 +++
 crypto/meson.build        |   3 +
 include/crypto/akcipher.h |  16 ++
 meson.build               |  11 +
 7 files changed, 783 insertions(+)
 create mode 100644 crypto/akcipher-nettle.c
 create mode 100644 crypto/asn1_decoder.c
 create mode 100644 crypto/asn1_decoder.h

diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
new file mode 100644
index 0000000000..45b93af772
--- /dev/null
+++ b/crypto/akcipher-nettle.c
@@ -0,0 +1,523 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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 <stdbool.h>
+
+#include <nettle/rsa.h>
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "asn1_decoder.h"
+#include "crypto/akcipher.h"
+#include "crypto/random.h"
+#include "qapi/error.h"
+#include "sysemu/cryptodev.h"
+
+typedef struct QCryptoNettleRsa {
+    QCryptoAkcipher akcipher;
+    struct rsa_public_key pub;
+    struct rsa_private_key priv;
+    QCryptoRsaPaddingAlgorithm padding_algo;
+    QCryptoRsaHashAlgorithm hash_algo;
+} QCryptoNettleRsa;
+
+struct asn1_parse_ctx {
+    const uint8_t *data;
+    size_t dlen;
+};
+
+#define Octet 8
+
+static int extract_value(void *p, const uint8_t *data, size_t dlen)
+{
+    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
+    ctx->data = (uint8_t *)data;
+    ctx->dlen = dlen;
+
+    return 0;
+}
+
+static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
+{
+    mpz_t *target = (mpz_t *)p;
+    nettle_mpz_set_str_256_u(*target, dlen, data);
+
+    return 0;
+}
+
+static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
+
+static void qcrypto_nettle_rsa_destroy(void *ptr)
+{
+    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
+    if (!rsa) {
+        return;
+    }
+
+    rsa_public_key_clear(&rsa->pub);
+    rsa_private_key_clear(&rsa->priv);
+    g_free(rsa);
+}
+
+static QCryptoAkcipher *qcrypto_nettle_new_rsa(
+    QCryptoAkcipherKeyType type,
+    const uint8_t *key,  size_t keylen,
+    QCryptoRsaOptions *opt, Error **errp);
+
+QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key,
+                                             size_t keylen, void *para,
+                                             Error **errp)
+{
+    switch (alg) {
+    case QCRYPTO_AKCIPHER_ALG_RSA:
+        return qcrypto_nettle_new_rsa(type, key, keylen,
+                                      (QCryptoRsaOptions *)para, errp);
+    default:
+        error_setg(errp, "Unsupported algorithm: %u", alg);
+        return NULL;
+    }
+
+    return NULL;
+}
+
+/**
+ * Parse ber encoded rsa private key, asn1 schema:
+ *        RsaPrivKey ::= SEQUENCE {
+ *             version     INTEGER
+ *             n           INTEGER
+ *             e           INTEGER
+ *             d           INTEGER
+ *             p           INTEGER
+ *             q           INTEGER
+ *             e1          INTEGER
+ *             e2          INTEGER
+ *             u           INTEGER
+ *         }
+ */
+static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
+                                 const uint8_t *key, size_t keylen)
+{
+    struct asn1_parse_ctx ctx;
+
+    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
+        keylen != 0) {
+        return -1;
+    }
+
+    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
+        ctx.dlen != 0) {
+        return -1;
+    }
+
+    if (!rsa_public_key_prepare(&rsa->pub)) {
+        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
+     */
+    rsa->priv.size = rsa->pub.size;
+
+    return 0;
+}
+
+/**
+ * Parse ber encoded rsa pubkey, asn1 schema:
+ *        RsaPrivKey ::= SEQUENCE {
+ *             n           INTEGER
+ *             e           INTEGER
+ *         }
+ */
+static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
+                                const uint8_t *key,
+                                size_t keylen)
+{
+    struct asn1_parse_ctx ctx;
+
+    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
+        keylen != 0) {
+        return -1;
+    }
+
+    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
+        ctx.dlen != 0) {
+        return -1;
+    }
+
+    if (!rsa_public_key_prepare(&rsa->pub)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
+    QCryptoAkcipherKeyType type,
+    const uint8_t *key, size_t keylen,
+    QCryptoRsaOptions *opt, Error **errp)
+{
+    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
+    rsa->padding_algo = opt->padding_algo;
+    rsa->hash_algo = opt->hash_algo;
+
+    switch (type) {
+    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
+            qcrypto_nettle_rsa_set_akcipher_size(
+                (QCryptoAkcipher *)rsa, rsa->priv.size);
+            return (QCryptoAkcipher *)rsa;
+        }
+        error_setg(errp, "Failed to parse rsa private key");
+        break;
+
+    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
+            qcrypto_nettle_rsa_set_akcipher_size(
+                (QCryptoAkcipher *)rsa, rsa->pub.size);
+            return (QCryptoAkcipher *)rsa;
+        }
+        error_setg(errp, "Failed to parse rsa public rsa key");
+        break;
+
+    default:
+        error_setg(errp, "Unknown akcipher key type %d", type);
+    }
+
+    qcrypto_nettle_rsa_destroy(rsa);
+    return NULL;
+}
+
+
+/**
+ * nettle does not provide RSA interfaces without padding,
+ * here we implemented rsa algorithm with nettle/mpz.
+ */
+static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
+                        size_t data_len, void *enc,
+                        size_t enc_len, Error **errp)
+{
+    mpz_t m;
+    int ret;
+
+    nettle_mpz_init_set_str_256_u(m, data_len, data);
+    /* (1) Validate 0 <= m < n */
+    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
+        error_setg(errp, "Failed to validate input data");
+        return -1;
+    }
+
+    /* (2) c = m ^ e mod n */
+    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
+    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
+        ret = -1;
+    } else {
+        ret = enc_len;
+        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
+    }
+
+    mpz_clear(m);
+
+    return ret;
+}
+
+static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
+                        const void *enc,
+                        size_t enc_len,
+                        void *data,
+                        size_t data_len,
+                        Error **errp)
+{
+    mpz_t c;
+    int ret;
+    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
+
+    /* (1) Validate 0 <= c < n */
+    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
+        error_setg(errp, "Failed to validate input data");
+        return -1;
+    }
+
+    /* (2) m = c ^ d mod n */
+    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
+    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
+        ret = -1;
+    } else {
+        ret = data_len;
+        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
+    }
+
+    mpz_clear(c);
+
+    return ret;
+}
+
+static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
+{
+    /* TODO: check result */
+    qcrypto_random_bytes(out, len, NULL);
+}
+
+static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
+                                      const void *data, size_t data_len,
+                                      void *enc, size_t enc_len,
+                                      Error **errp)
+{
+
+    QCryptoNettleRsa *rsa =
+        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
+    mpz_t c;
+    int enc_ret;
+
+    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    switch (rsa->padding_algo) {
+    case QCRYPTO_RSA_PADDING_ALG_RAW:
+        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
+
+    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+        mpz_init(c);
+        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
+                              data_len, (uint8_t *)data, c);
+        if (enc_ret != 1) {
+            error_setg(errp, "Failed to encrypt");
+            enc_ret = -1;
+        } else {
+            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
+            enc_ret = enc_len;
+        }
+        mpz_clear(c);
+        return enc_ret;
+
+    default:
+        error_setg(errp, "Unknown padding");
+        return -1;
+    }
+
+    return -1;
+}
+
+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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+    mpz_t c;
+    int ret;
+    if (enc_len > rsa->priv.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    switch (rsa->padding_algo) {
+    case QCRYPTO_RSA_PADDING_ALG_RAW:
+        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
+        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");
+            ret = -1;
+        } else {
+            ret = data_len;
+        }
+
+        mpz_clear(c);
+        break;
+
+    default:
+        ret = -1;
+        error_setg(errp, "Unknown padding");
+    }
+
+    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+    int ret;
+    mpz_t s;
+
+    /**
+     * The RSA algorithm cannot be used for signature/verification
+     * without padding.
+     */
+    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
+        error_setg(errp, "Try to make signature without padding");
+        return -1;
+    }
+
+    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    mpz_init(s);
+    switch (rsa->hash_algo) {
+    case QCRYPTO_RSA_HASH_ALG_MD5:
+        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA1:
+        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA256:
+        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA512:
+        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
+        break;
+
+    default:
+        error_setg(errp, "Unknown hash algorithm");
+        ret = -1;
+        goto clear;
+    }
+
+    if (ret != 1) {
+        error_setg(errp, "Failed to make signature");
+        ret = -1;
+        goto clear;
+    }
+    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
+    ret = sig_len;
+
+clear:
+    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+
+    int ret;
+    mpz_t s;
+
+    /**
+     * The RSA algorithm cannot be used for signature/verification
+     * without padding.
+     */
+    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
+        error_setg(errp, "Operation not supported");
+        return -1;
+    }
+    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
+    switch (rsa->hash_algo) {
+    case QCRYPTO_RSA_HASH_ALG_MD5:
+        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA1:
+        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA256:
+        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA512:
+        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
+        break;
+
+    default:
+        error_setg(errp, "Unsupported hash algorithm");
+        ret = -1;
+        goto clear;
+    }
+
+    if (ret != 1) {
+        error_setg(errp, "Failed to verify");
+        ret = -1;
+        goto clear;
+    }
+    ret = 0;
+
+clear:
+    mpz_clear(s);
+
+    return ret;
+}
+
+static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
+                                   Error **errp)
+{
+    qcrypto_nettle_rsa_destroy(akcipher);
+    return 0;
+}
+
+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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
+{
+    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));
+    memset(rsa, 0, sizeof(QCryptoNettleRsa));
+    rsa->akcipher.driver = &nettle_rsa;
+    rsa_public_key_init(&rsa->pub);
+    rsa_private_key_init(&rsa->priv);
+
+    return rsa;
+}
diff --git a/crypto/akcipher.c b/crypto/akcipher.c
index 1e52f2fd76..b5c04e8424 100644
--- a/crypto/akcipher.c
+++ b/crypto/akcipher.c
@@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
 {
     QCryptoAkcipher *akcipher = NULL;
 
+    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
+                                           para, errp);
+
     return akcipher;
 }
 
diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
new file mode 100644
index 0000000000..bfb145e84e
--- /dev/null
+++ b/crypto/asn1_decoder.c
@@ -0,0 +1,185 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#include "crypto/asn1_decoder.h"
+
+enum ber_type_tag {
+    ber_type_tag_bool = 0x1,
+    ber_type_tag_int = 0x2,
+    ber_type_tag_bit_str = 0x3,
+    ber_type_tag_oct_str = 0x4,
+    ber_type_tag_oct_null = 0x5,
+    ber_type_tag_oct_oid = 0x6,
+    ber_type_tag_seq = 0x10,
+    ber_type_tag_set = 0x11,
+};
+
+#define BER_CONSTRUCTED_MASK 0x20
+#define BER_SHORT_LEN_MASK 0x80
+
+static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
+{
+    return **data;
+}
+
+static int invoke_callback(BerDecodeCb cb, void *ctx,
+                           const uint8_t *value, size_t vlen)
+{
+    if (!cb) {
+        return 0;
+    }
+
+    return cb(ctx, value, vlen);
+}
+
+static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
+                           size_t nbytes)
+{
+    *data += nbytes;
+    *dlen -= nbytes;
+}
+
+static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
+{
+    uint8_t val = ber_peek_byte(data, dlen);
+
+    ber_cut_nbytes(data, dlen, 1);
+
+    return val;
+}
+
+static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
+                                     BerDecodeCb cb, void *ctx)
+{
+    const uint8_t *value;
+    size_t vlen = 0;
+    uint8_t byte_count = ber_cut_byte(data, dlen);
+
+    /* short format of definite-length */
+    if (!(byte_count & BER_SHORT_LEN_MASK)) {
+        if (byte_count > *dlen) {
+            return -1;
+        }
+
+        value = *data;
+        vlen = byte_count;
+        ber_cut_nbytes(data, dlen, vlen);
+
+        return invoke_callback(cb, ctx, value, vlen);
+    }
+
+    /* Ignore highest bit */
+    byte_count &= ~BER_SHORT_LEN_MASK;
+
+    /*
+     * size_t is enough to express the length, although the ber encoding
+     * standard supports larger length.
+     */
+    if (byte_count > sizeof(size_t)) {
+        return -1;
+    }
+
+    while (byte_count--) {
+        vlen <<= 8;
+        vlen += ber_cut_byte(data, dlen);
+    }
+
+    if (vlen > *dlen) {
+        return -1;
+    }
+
+    value = *data;
+    ber_cut_nbytes(data, dlen, vlen);
+
+    return invoke_callback(cb, ctx, value, vlen);
+}
+
+static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
+                                       BerDecodeCb cb, void *ctx)
+{
+    size_t vlen = 0;
+    const uint8_t *value;
+
+    if (*dlen < 3) {
+        return -1;
+    }
+
+    /* skip undefinite-length-mask 0x80 */
+    ber_cut_nbytes(data, dlen, 1);
+
+    value = *data;
+    while (vlen < *dlen) {
+        if ((*data)[vlen] != 0) {
+            vlen++;
+            continue;
+        }
+
+        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
+            ber_cut_nbytes(data, dlen, vlen + 2);
+            return invoke_callback(cb, ctx, value, vlen);
+        }
+
+        vlen += 2;
+    }
+
+    return -1;
+}
+
+static int ber_extract_data(const uint8_t **data, size_t *dlen,
+                            BerDecodeCb cb, void *ctx)
+{
+    uint8_t val = ber_peek_byte(data, dlen);
+
+    if (val == BER_SHORT_LEN_MASK) {
+        return ber_extract_undefinite_data(data, dlen, cb, ctx);
+    }
+
+    return ber_extract_definite_data(data, dlen, cb, ctx);
+}
+
+int ber_decode_int(const uint8_t **data, size_t *dlen,
+                   BerDecodeCb cb, void *ctx)
+{
+    uint8_t tag = ber_cut_byte(data, dlen);
+
+    /* INTEGER must encoded in primitive-form */
+    if (tag != ber_type_tag_int) {
+        return -1;
+    }
+
+    return ber_extract_data(data, dlen, cb, ctx);
+}
+
+int ber_decode_seq(const uint8_t **data, size_t *dlen,
+                   BerDecodeCb cb, void *ctx)
+{
+    uint8_t val = ber_cut_byte(data, dlen);
+
+    /* SEQUENCE must use constructed form */
+    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
+        return -1;
+    }
+
+    return ber_extract_data(data, dlen, cb, ctx);
+}
diff --git a/crypto/asn1_decoder.h b/crypto/asn1_decoder.h
new file mode 100644
index 0000000000..d33a7c81c4
--- /dev/null
+++ b/crypto/asn1_decoder.h
@@ -0,0 +1,42 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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
+
+/*
+ *  ctx: user content.
+ *  value: the starting address of |value| part of 'Tag-Length-Value' pattern.
+ *  vlen: length of the |value|.
+ */
+typedef int (*BerDecodeCb) (void *ctx, const uint8_t *value, size_t vlen);
+
+int ber_decode_int(const uint8_t **data,
+                   size_t *dlen,
+                   BerDecodeCb cb,
+                   void *ctx);
+
+int ber_decode_seq(const uint8_t **data,
+                   size_t *dlen,
+                   BerDecodeCb cb,
+                   void *ctx);
+
+#endif  /* QCRYPTO_ASN1_DECODER_H */
diff --git a/crypto/meson.build b/crypto/meson.build
index c32b57aeda..f398d7abda 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -27,6 +27,9 @@ if nettle.found()
   if xts == 'private'
     crypto_ss.add(files('xts.c'))
   endif
+  if hogweed.found()
+    crypto_ss.add(gmp, hogweed, files('akcipher-nettle.c', 'asn1_decoder.c'))
+  endif
 elif gcrypt.found()
   crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
 elif gnutls_crypto.found()
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index 03cc3bf46b..2ec7f0f8d7 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
 
 int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
 
+#ifdef CONFIG_HOGWEED
+QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key, size_t keylen,
+                                             void *para, Error **errp);
+#else
+static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
+                                             QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key, size_t keylen,
+                                             void *para, Error **errp)
+{
+    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
+    return NULL;
+}
+#endif
 
 #endif /* QCRYPTO_AKCIPHER_H */
diff --git a/meson.build b/meson.build
index 282e7c4650..ea6b8feb3c 100644
--- a/meson.build
+++ b/meson.build
@@ -1049,6 +1049,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()
@@ -1086,6 +1087,14 @@ 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
@@ -1567,6 +1576,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)
@@ -3614,6 +3624,7 @@ summary_info += {'libgcrypt':         gcrypt}
 summary_info += {'nettle':            nettle}
 if nettle.found()
    summary_info += {'  XTS':             xts != 'private'}
+   summary_info += {'  hogweed':         hogweed.found()}
 endif
 summary_info += {'AF_ALG support':    have_afalg}
 summary_info += {'rng-none':          get_option('rng_none')}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, qemu-devel, zhenwei pi, virtualization, linux-crypto, Lei He

From: Lei He <helei.sig11@bytedance.com>

Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
 crypto/akcipher.c         |   3 +
 crypto/asn1_decoder.c     | 185 ++++++++++++++
 crypto/asn1_decoder.h     |  42 +++
 crypto/meson.build        |   3 +
 include/crypto/akcipher.h |  16 ++
 meson.build               |  11 +
 7 files changed, 783 insertions(+)
 create mode 100644 crypto/akcipher-nettle.c
 create mode 100644 crypto/asn1_decoder.c
 create mode 100644 crypto/asn1_decoder.h

diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
new file mode 100644
index 0000000000..45b93af772
--- /dev/null
+++ b/crypto/akcipher-nettle.c
@@ -0,0 +1,523 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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 <stdbool.h>
+
+#include <nettle/rsa.h>
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "asn1_decoder.h"
+#include "crypto/akcipher.h"
+#include "crypto/random.h"
+#include "qapi/error.h"
+#include "sysemu/cryptodev.h"
+
+typedef struct QCryptoNettleRsa {
+    QCryptoAkcipher akcipher;
+    struct rsa_public_key pub;
+    struct rsa_private_key priv;
+    QCryptoRsaPaddingAlgorithm padding_algo;
+    QCryptoRsaHashAlgorithm hash_algo;
+} QCryptoNettleRsa;
+
+struct asn1_parse_ctx {
+    const uint8_t *data;
+    size_t dlen;
+};
+
+#define Octet 8
+
+static int extract_value(void *p, const uint8_t *data, size_t dlen)
+{
+    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
+    ctx->data = (uint8_t *)data;
+    ctx->dlen = dlen;
+
+    return 0;
+}
+
+static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
+{
+    mpz_t *target = (mpz_t *)p;
+    nettle_mpz_set_str_256_u(*target, dlen, data);
+
+    return 0;
+}
+
+static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
+
+static void qcrypto_nettle_rsa_destroy(void *ptr)
+{
+    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
+    if (!rsa) {
+        return;
+    }
+
+    rsa_public_key_clear(&rsa->pub);
+    rsa_private_key_clear(&rsa->priv);
+    g_free(rsa);
+}
+
+static QCryptoAkcipher *qcrypto_nettle_new_rsa(
+    QCryptoAkcipherKeyType type,
+    const uint8_t *key,  size_t keylen,
+    QCryptoRsaOptions *opt, Error **errp);
+
+QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key,
+                                             size_t keylen, void *para,
+                                             Error **errp)
+{
+    switch (alg) {
+    case QCRYPTO_AKCIPHER_ALG_RSA:
+        return qcrypto_nettle_new_rsa(type, key, keylen,
+                                      (QCryptoRsaOptions *)para, errp);
+    default:
+        error_setg(errp, "Unsupported algorithm: %u", alg);
+        return NULL;
+    }
+
+    return NULL;
+}
+
+/**
+ * Parse ber encoded rsa private key, asn1 schema:
+ *        RsaPrivKey ::= SEQUENCE {
+ *             version     INTEGER
+ *             n           INTEGER
+ *             e           INTEGER
+ *             d           INTEGER
+ *             p           INTEGER
+ *             q           INTEGER
+ *             e1          INTEGER
+ *             e2          INTEGER
+ *             u           INTEGER
+ *         }
+ */
+static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
+                                 const uint8_t *key, size_t keylen)
+{
+    struct asn1_parse_ctx ctx;
+
+    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
+        keylen != 0) {
+        return -1;
+    }
+
+    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
+        ctx.dlen != 0) {
+        return -1;
+    }
+
+    if (!rsa_public_key_prepare(&rsa->pub)) {
+        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
+     */
+    rsa->priv.size = rsa->pub.size;
+
+    return 0;
+}
+
+/**
+ * Parse ber encoded rsa pubkey, asn1 schema:
+ *        RsaPrivKey ::= SEQUENCE {
+ *             n           INTEGER
+ *             e           INTEGER
+ *         }
+ */
+static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
+                                const uint8_t *key,
+                                size_t keylen)
+{
+    struct asn1_parse_ctx ctx;
+
+    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
+        keylen != 0) {
+        return -1;
+    }
+
+    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
+        ctx.dlen != 0) {
+        return -1;
+    }
+
+    if (!rsa_public_key_prepare(&rsa->pub)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
+    QCryptoAkcipherKeyType type,
+    const uint8_t *key, size_t keylen,
+    QCryptoRsaOptions *opt, Error **errp)
+{
+    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
+    rsa->padding_algo = opt->padding_algo;
+    rsa->hash_algo = opt->hash_algo;
+
+    switch (type) {
+    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
+            qcrypto_nettle_rsa_set_akcipher_size(
+                (QCryptoAkcipher *)rsa, rsa->priv.size);
+            return (QCryptoAkcipher *)rsa;
+        }
+        error_setg(errp, "Failed to parse rsa private key");
+        break;
+
+    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
+            qcrypto_nettle_rsa_set_akcipher_size(
+                (QCryptoAkcipher *)rsa, rsa->pub.size);
+            return (QCryptoAkcipher *)rsa;
+        }
+        error_setg(errp, "Failed to parse rsa public rsa key");
+        break;
+
+    default:
+        error_setg(errp, "Unknown akcipher key type %d", type);
+    }
+
+    qcrypto_nettle_rsa_destroy(rsa);
+    return NULL;
+}
+
+
+/**
+ * nettle does not provide RSA interfaces without padding,
+ * here we implemented rsa algorithm with nettle/mpz.
+ */
+static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
+                        size_t data_len, void *enc,
+                        size_t enc_len, Error **errp)
+{
+    mpz_t m;
+    int ret;
+
+    nettle_mpz_init_set_str_256_u(m, data_len, data);
+    /* (1) Validate 0 <= m < n */
+    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
+        error_setg(errp, "Failed to validate input data");
+        return -1;
+    }
+
+    /* (2) c = m ^ e mod n */
+    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
+    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
+        ret = -1;
+    } else {
+        ret = enc_len;
+        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
+    }
+
+    mpz_clear(m);
+
+    return ret;
+}
+
+static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
+                        const void *enc,
+                        size_t enc_len,
+                        void *data,
+                        size_t data_len,
+                        Error **errp)
+{
+    mpz_t c;
+    int ret;
+    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
+
+    /* (1) Validate 0 <= c < n */
+    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
+        error_setg(errp, "Failed to validate input data");
+        return -1;
+    }
+
+    /* (2) m = c ^ d mod n */
+    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
+    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
+        ret = -1;
+    } else {
+        ret = data_len;
+        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
+    }
+
+    mpz_clear(c);
+
+    return ret;
+}
+
+static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
+{
+    /* TODO: check result */
+    qcrypto_random_bytes(out, len, NULL);
+}
+
+static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
+                                      const void *data, size_t data_len,
+                                      void *enc, size_t enc_len,
+                                      Error **errp)
+{
+
+    QCryptoNettleRsa *rsa =
+        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
+    mpz_t c;
+    int enc_ret;
+
+    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    switch (rsa->padding_algo) {
+    case QCRYPTO_RSA_PADDING_ALG_RAW:
+        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
+
+    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+        mpz_init(c);
+        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
+                              data_len, (uint8_t *)data, c);
+        if (enc_ret != 1) {
+            error_setg(errp, "Failed to encrypt");
+            enc_ret = -1;
+        } else {
+            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
+            enc_ret = enc_len;
+        }
+        mpz_clear(c);
+        return enc_ret;
+
+    default:
+        error_setg(errp, "Unknown padding");
+        return -1;
+    }
+
+    return -1;
+}
+
+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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+    mpz_t c;
+    int ret;
+    if (enc_len > rsa->priv.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    switch (rsa->padding_algo) {
+    case QCRYPTO_RSA_PADDING_ALG_RAW:
+        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
+        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");
+            ret = -1;
+        } else {
+            ret = data_len;
+        }
+
+        mpz_clear(c);
+        break;
+
+    default:
+        ret = -1;
+        error_setg(errp, "Unknown padding");
+    }
+
+    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+    int ret;
+    mpz_t s;
+
+    /**
+     * The RSA algorithm cannot be used for signature/verification
+     * without padding.
+     */
+    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
+        error_setg(errp, "Try to make signature without padding");
+        return -1;
+    }
+
+    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    mpz_init(s);
+    switch (rsa->hash_algo) {
+    case QCRYPTO_RSA_HASH_ALG_MD5:
+        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA1:
+        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA256:
+        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA512:
+        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
+        break;
+
+    default:
+        error_setg(errp, "Unknown hash algorithm");
+        ret = -1;
+        goto clear;
+    }
+
+    if (ret != 1) {
+        error_setg(errp, "Failed to make signature");
+        ret = -1;
+        goto clear;
+    }
+    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
+    ret = sig_len;
+
+clear:
+    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+
+    int ret;
+    mpz_t s;
+
+    /**
+     * The RSA algorithm cannot be used for signature/verification
+     * without padding.
+     */
+    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
+        error_setg(errp, "Operation not supported");
+        return -1;
+    }
+    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
+    switch (rsa->hash_algo) {
+    case QCRYPTO_RSA_HASH_ALG_MD5:
+        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA1:
+        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA256:
+        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA512:
+        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
+        break;
+
+    default:
+        error_setg(errp, "Unsupported hash algorithm");
+        ret = -1;
+        goto clear;
+    }
+
+    if (ret != 1) {
+        error_setg(errp, "Failed to verify");
+        ret = -1;
+        goto clear;
+    }
+    ret = 0;
+
+clear:
+    mpz_clear(s);
+
+    return ret;
+}
+
+static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
+                                   Error **errp)
+{
+    qcrypto_nettle_rsa_destroy(akcipher);
+    return 0;
+}
+
+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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
+{
+    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));
+    memset(rsa, 0, sizeof(QCryptoNettleRsa));
+    rsa->akcipher.driver = &nettle_rsa;
+    rsa_public_key_init(&rsa->pub);
+    rsa_private_key_init(&rsa->priv);
+
+    return rsa;
+}
diff --git a/crypto/akcipher.c b/crypto/akcipher.c
index 1e52f2fd76..b5c04e8424 100644
--- a/crypto/akcipher.c
+++ b/crypto/akcipher.c
@@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
 {
     QCryptoAkcipher *akcipher = NULL;
 
+    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
+                                           para, errp);
+
     return akcipher;
 }
 
diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
new file mode 100644
index 0000000000..bfb145e84e
--- /dev/null
+++ b/crypto/asn1_decoder.c
@@ -0,0 +1,185 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#include "crypto/asn1_decoder.h"
+
+enum ber_type_tag {
+    ber_type_tag_bool = 0x1,
+    ber_type_tag_int = 0x2,
+    ber_type_tag_bit_str = 0x3,
+    ber_type_tag_oct_str = 0x4,
+    ber_type_tag_oct_null = 0x5,
+    ber_type_tag_oct_oid = 0x6,
+    ber_type_tag_seq = 0x10,
+    ber_type_tag_set = 0x11,
+};
+
+#define BER_CONSTRUCTED_MASK 0x20
+#define BER_SHORT_LEN_MASK 0x80
+
+static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
+{
+    return **data;
+}
+
+static int invoke_callback(BerDecodeCb cb, void *ctx,
+                           const uint8_t *value, size_t vlen)
+{
+    if (!cb) {
+        return 0;
+    }
+
+    return cb(ctx, value, vlen);
+}
+
+static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
+                           size_t nbytes)
+{
+    *data += nbytes;
+    *dlen -= nbytes;
+}
+
+static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
+{
+    uint8_t val = ber_peek_byte(data, dlen);
+
+    ber_cut_nbytes(data, dlen, 1);
+
+    return val;
+}
+
+static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
+                                     BerDecodeCb cb, void *ctx)
+{
+    const uint8_t *value;
+    size_t vlen = 0;
+    uint8_t byte_count = ber_cut_byte(data, dlen);
+
+    /* short format of definite-length */
+    if (!(byte_count & BER_SHORT_LEN_MASK)) {
+        if (byte_count > *dlen) {
+            return -1;
+        }
+
+        value = *data;
+        vlen = byte_count;
+        ber_cut_nbytes(data, dlen, vlen);
+
+        return invoke_callback(cb, ctx, value, vlen);
+    }
+
+    /* Ignore highest bit */
+    byte_count &= ~BER_SHORT_LEN_MASK;
+
+    /*
+     * size_t is enough to express the length, although the ber encoding
+     * standard supports larger length.
+     */
+    if (byte_count > sizeof(size_t)) {
+        return -1;
+    }
+
+    while (byte_count--) {
+        vlen <<= 8;
+        vlen += ber_cut_byte(data, dlen);
+    }
+
+    if (vlen > *dlen) {
+        return -1;
+    }
+
+    value = *data;
+    ber_cut_nbytes(data, dlen, vlen);
+
+    return invoke_callback(cb, ctx, value, vlen);
+}
+
+static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
+                                       BerDecodeCb cb, void *ctx)
+{
+    size_t vlen = 0;
+    const uint8_t *value;
+
+    if (*dlen < 3) {
+        return -1;
+    }
+
+    /* skip undefinite-length-mask 0x80 */
+    ber_cut_nbytes(data, dlen, 1);
+
+    value = *data;
+    while (vlen < *dlen) {
+        if ((*data)[vlen] != 0) {
+            vlen++;
+            continue;
+        }
+
+        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
+            ber_cut_nbytes(data, dlen, vlen + 2);
+            return invoke_callback(cb, ctx, value, vlen);
+        }
+
+        vlen += 2;
+    }
+
+    return -1;
+}
+
+static int ber_extract_data(const uint8_t **data, size_t *dlen,
+                            BerDecodeCb cb, void *ctx)
+{
+    uint8_t val = ber_peek_byte(data, dlen);
+
+    if (val == BER_SHORT_LEN_MASK) {
+        return ber_extract_undefinite_data(data, dlen, cb, ctx);
+    }
+
+    return ber_extract_definite_data(data, dlen, cb, ctx);
+}
+
+int ber_decode_int(const uint8_t **data, size_t *dlen,
+                   BerDecodeCb cb, void *ctx)
+{
+    uint8_t tag = ber_cut_byte(data, dlen);
+
+    /* INTEGER must encoded in primitive-form */
+    if (tag != ber_type_tag_int) {
+        return -1;
+    }
+
+    return ber_extract_data(data, dlen, cb, ctx);
+}
+
+int ber_decode_seq(const uint8_t **data, size_t *dlen,
+                   BerDecodeCb cb, void *ctx)
+{
+    uint8_t val = ber_cut_byte(data, dlen);
+
+    /* SEQUENCE must use constructed form */
+    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
+        return -1;
+    }
+
+    return ber_extract_data(data, dlen, cb, ctx);
+}
diff --git a/crypto/asn1_decoder.h b/crypto/asn1_decoder.h
new file mode 100644
index 0000000000..d33a7c81c4
--- /dev/null
+++ b/crypto/asn1_decoder.h
@@ -0,0 +1,42 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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
+
+/*
+ *  ctx: user content.
+ *  value: the starting address of |value| part of 'Tag-Length-Value' pattern.
+ *  vlen: length of the |value|.
+ */
+typedef int (*BerDecodeCb) (void *ctx, const uint8_t *value, size_t vlen);
+
+int ber_decode_int(const uint8_t **data,
+                   size_t *dlen,
+                   BerDecodeCb cb,
+                   void *ctx);
+
+int ber_decode_seq(const uint8_t **data,
+                   size_t *dlen,
+                   BerDecodeCb cb,
+                   void *ctx);
+
+#endif  /* QCRYPTO_ASN1_DECODER_H */
diff --git a/crypto/meson.build b/crypto/meson.build
index c32b57aeda..f398d7abda 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -27,6 +27,9 @@ if nettle.found()
   if xts == 'private'
     crypto_ss.add(files('xts.c'))
   endif
+  if hogweed.found()
+    crypto_ss.add(gmp, hogweed, files('akcipher-nettle.c', 'asn1_decoder.c'))
+  endif
 elif gcrypt.found()
   crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
 elif gnutls_crypto.found()
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index 03cc3bf46b..2ec7f0f8d7 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
 
 int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
 
+#ifdef CONFIG_HOGWEED
+QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key, size_t keylen,
+                                             void *para, Error **errp);
+#else
+static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
+                                             QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key, size_t keylen,
+                                             void *para, Error **errp)
+{
+    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
+    return NULL;
+}
+#endif
 
 #endif /* QCRYPTO_AKCIPHER_H */
diff --git a/meson.build b/meson.build
index 282e7c4650..ea6b8feb3c 100644
--- a/meson.build
+++ b/meson.build
@@ -1049,6 +1049,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()
@@ -1086,6 +1087,14 @@ 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
@@ -1567,6 +1576,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)
@@ -3614,6 +3624,7 @@ summary_info += {'libgcrypt':         gcrypt}
 summary_info += {'nettle':            nettle}
 if nettle.found()
    summary_info += {'  XTS':             xts != 'private'}
+   summary_info += {'  hogweed':         hogweed.found()}
 endif
 summary_info += {'AF_ALG support':    have_afalg}
 summary_info += {'rng-none':          get_option('rng_none')}
-- 
2.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, jasowang, qemu-devel, zhenwei pi, virtualization,
	linux-crypto, Lei He

From: Lei He <helei.sig11@bytedance.com>

Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
 crypto/akcipher.c         |   3 +
 crypto/asn1_decoder.c     | 185 ++++++++++++++
 crypto/asn1_decoder.h     |  42 +++
 crypto/meson.build        |   3 +
 include/crypto/akcipher.h |  16 ++
 meson.build               |  11 +
 7 files changed, 783 insertions(+)
 create mode 100644 crypto/akcipher-nettle.c
 create mode 100644 crypto/asn1_decoder.c
 create mode 100644 crypto/asn1_decoder.h

diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
new file mode 100644
index 0000000000..45b93af772
--- /dev/null
+++ b/crypto/akcipher-nettle.c
@@ -0,0 +1,523 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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 <stdbool.h>
+
+#include <nettle/rsa.h>
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "asn1_decoder.h"
+#include "crypto/akcipher.h"
+#include "crypto/random.h"
+#include "qapi/error.h"
+#include "sysemu/cryptodev.h"
+
+typedef struct QCryptoNettleRsa {
+    QCryptoAkcipher akcipher;
+    struct rsa_public_key pub;
+    struct rsa_private_key priv;
+    QCryptoRsaPaddingAlgorithm padding_algo;
+    QCryptoRsaHashAlgorithm hash_algo;
+} QCryptoNettleRsa;
+
+struct asn1_parse_ctx {
+    const uint8_t *data;
+    size_t dlen;
+};
+
+#define Octet 8
+
+static int extract_value(void *p, const uint8_t *data, size_t dlen)
+{
+    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
+    ctx->data = (uint8_t *)data;
+    ctx->dlen = dlen;
+
+    return 0;
+}
+
+static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
+{
+    mpz_t *target = (mpz_t *)p;
+    nettle_mpz_set_str_256_u(*target, dlen, data);
+
+    return 0;
+}
+
+static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
+
+static void qcrypto_nettle_rsa_destroy(void *ptr)
+{
+    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
+    if (!rsa) {
+        return;
+    }
+
+    rsa_public_key_clear(&rsa->pub);
+    rsa_private_key_clear(&rsa->priv);
+    g_free(rsa);
+}
+
+static QCryptoAkcipher *qcrypto_nettle_new_rsa(
+    QCryptoAkcipherKeyType type,
+    const uint8_t *key,  size_t keylen,
+    QCryptoRsaOptions *opt, Error **errp);
+
+QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key,
+                                             size_t keylen, void *para,
+                                             Error **errp)
+{
+    switch (alg) {
+    case QCRYPTO_AKCIPHER_ALG_RSA:
+        return qcrypto_nettle_new_rsa(type, key, keylen,
+                                      (QCryptoRsaOptions *)para, errp);
+    default:
+        error_setg(errp, "Unsupported algorithm: %u", alg);
+        return NULL;
+    }
+
+    return NULL;
+}
+
+/**
+ * Parse ber encoded rsa private key, asn1 schema:
+ *        RsaPrivKey ::= SEQUENCE {
+ *             version     INTEGER
+ *             n           INTEGER
+ *             e           INTEGER
+ *             d           INTEGER
+ *             p           INTEGER
+ *             q           INTEGER
+ *             e1          INTEGER
+ *             e2          INTEGER
+ *             u           INTEGER
+ *         }
+ */
+static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
+                                 const uint8_t *key, size_t keylen)
+{
+    struct asn1_parse_ctx ctx;
+
+    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
+        keylen != 0) {
+        return -1;
+    }
+
+    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
+        ctx.dlen != 0) {
+        return -1;
+    }
+
+    if (!rsa_public_key_prepare(&rsa->pub)) {
+        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
+     */
+    rsa->priv.size = rsa->pub.size;
+
+    return 0;
+}
+
+/**
+ * Parse ber encoded rsa pubkey, asn1 schema:
+ *        RsaPrivKey ::= SEQUENCE {
+ *             n           INTEGER
+ *             e           INTEGER
+ *         }
+ */
+static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
+                                const uint8_t *key,
+                                size_t keylen)
+{
+    struct asn1_parse_ctx ctx;
+
+    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
+        keylen != 0) {
+        return -1;
+    }
+
+    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
+        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
+        ctx.dlen != 0) {
+        return -1;
+    }
+
+    if (!rsa_public_key_prepare(&rsa->pub)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
+    QCryptoAkcipherKeyType type,
+    const uint8_t *key, size_t keylen,
+    QCryptoRsaOptions *opt, Error **errp)
+{
+    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
+    rsa->padding_algo = opt->padding_algo;
+    rsa->hash_algo = opt->hash_algo;
+
+    switch (type) {
+    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
+            qcrypto_nettle_rsa_set_akcipher_size(
+                (QCryptoAkcipher *)rsa, rsa->priv.size);
+            return (QCryptoAkcipher *)rsa;
+        }
+        error_setg(errp, "Failed to parse rsa private key");
+        break;
+
+    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
+            qcrypto_nettle_rsa_set_akcipher_size(
+                (QCryptoAkcipher *)rsa, rsa->pub.size);
+            return (QCryptoAkcipher *)rsa;
+        }
+        error_setg(errp, "Failed to parse rsa public rsa key");
+        break;
+
+    default:
+        error_setg(errp, "Unknown akcipher key type %d", type);
+    }
+
+    qcrypto_nettle_rsa_destroy(rsa);
+    return NULL;
+}
+
+
+/**
+ * nettle does not provide RSA interfaces without padding,
+ * here we implemented rsa algorithm with nettle/mpz.
+ */
+static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
+                        size_t data_len, void *enc,
+                        size_t enc_len, Error **errp)
+{
+    mpz_t m;
+    int ret;
+
+    nettle_mpz_init_set_str_256_u(m, data_len, data);
+    /* (1) Validate 0 <= m < n */
+    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
+        error_setg(errp, "Failed to validate input data");
+        return -1;
+    }
+
+    /* (2) c = m ^ e mod n */
+    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
+    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
+        ret = -1;
+    } else {
+        ret = enc_len;
+        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
+    }
+
+    mpz_clear(m);
+
+    return ret;
+}
+
+static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
+                        const void *enc,
+                        size_t enc_len,
+                        void *data,
+                        size_t data_len,
+                        Error **errp)
+{
+    mpz_t c;
+    int ret;
+    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
+
+    /* (1) Validate 0 <= c < n */
+    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
+        error_setg(errp, "Failed to validate input data");
+        return -1;
+    }
+
+    /* (2) m = c ^ d mod n */
+    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
+    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
+        ret = -1;
+    } else {
+        ret = data_len;
+        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
+    }
+
+    mpz_clear(c);
+
+    return ret;
+}
+
+static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
+{
+    /* TODO: check result */
+    qcrypto_random_bytes(out, len, NULL);
+}
+
+static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
+                                      const void *data, size_t data_len,
+                                      void *enc, size_t enc_len,
+                                      Error **errp)
+{
+
+    QCryptoNettleRsa *rsa =
+        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
+    mpz_t c;
+    int enc_ret;
+
+    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    switch (rsa->padding_algo) {
+    case QCRYPTO_RSA_PADDING_ALG_RAW:
+        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
+
+    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+        mpz_init(c);
+        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
+                              data_len, (uint8_t *)data, c);
+        if (enc_ret != 1) {
+            error_setg(errp, "Failed to encrypt");
+            enc_ret = -1;
+        } else {
+            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
+            enc_ret = enc_len;
+        }
+        mpz_clear(c);
+        return enc_ret;
+
+    default:
+        error_setg(errp, "Unknown padding");
+        return -1;
+    }
+
+    return -1;
+}
+
+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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+    mpz_t c;
+    int ret;
+    if (enc_len > rsa->priv.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    switch (rsa->padding_algo) {
+    case QCRYPTO_RSA_PADDING_ALG_RAW:
+        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
+        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");
+            ret = -1;
+        } else {
+            ret = data_len;
+        }
+
+        mpz_clear(c);
+        break;
+
+    default:
+        ret = -1;
+        error_setg(errp, "Unknown padding");
+    }
+
+    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+    int ret;
+    mpz_t s;
+
+    /**
+     * The RSA algorithm cannot be used for signature/verification
+     * without padding.
+     */
+    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
+        error_setg(errp, "Try to make signature without padding");
+        return -1;
+    }
+
+    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    mpz_init(s);
+    switch (rsa->hash_algo) {
+    case QCRYPTO_RSA_HASH_ALG_MD5:
+        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA1:
+        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA256:
+        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA512:
+        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
+        break;
+
+    default:
+        error_setg(errp, "Unknown hash algorithm");
+        ret = -1;
+        goto clear;
+    }
+
+    if (ret != 1) {
+        error_setg(errp, "Failed to make signature");
+        ret = -1;
+        goto clear;
+    }
+    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
+    ret = sig_len;
+
+clear:
+    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
+
+    int ret;
+    mpz_t s;
+
+    /**
+     * The RSA algorithm cannot be used for signature/verification
+     * without padding.
+     */
+    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
+        error_setg(errp, "Operation not supported");
+        return -1;
+    }
+    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
+        error_setg(errp, "Invalid buffer size");
+        return -1;
+    }
+
+    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
+    switch (rsa->hash_algo) {
+    case QCRYPTO_RSA_HASH_ALG_MD5:
+        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA1:
+        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA256:
+        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
+        break;
+
+    case QCRYPTO_RSA_HASH_ALG_SHA512:
+        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
+        break;
+
+    default:
+        error_setg(errp, "Unsupported hash algorithm");
+        ret = -1;
+        goto clear;
+    }
+
+    if (ret != 1) {
+        error_setg(errp, "Failed to verify");
+        ret = -1;
+        goto clear;
+    }
+    ret = 0;
+
+clear:
+    mpz_clear(s);
+
+    return ret;
+}
+
+static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
+                                   Error **errp)
+{
+    qcrypto_nettle_rsa_destroy(akcipher);
+    return 0;
+}
+
+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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
+{
+    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));
+    memset(rsa, 0, sizeof(QCryptoNettleRsa));
+    rsa->akcipher.driver = &nettle_rsa;
+    rsa_public_key_init(&rsa->pub);
+    rsa_private_key_init(&rsa->priv);
+
+    return rsa;
+}
diff --git a/crypto/akcipher.c b/crypto/akcipher.c
index 1e52f2fd76..b5c04e8424 100644
--- a/crypto/akcipher.c
+++ b/crypto/akcipher.c
@@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
 {
     QCryptoAkcipher *akcipher = NULL;
 
+    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
+                                           para, errp);
+
     return akcipher;
 }
 
diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
new file mode 100644
index 0000000000..bfb145e84e
--- /dev/null
+++ b/crypto/asn1_decoder.c
@@ -0,0 +1,185 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#include "crypto/asn1_decoder.h"
+
+enum ber_type_tag {
+    ber_type_tag_bool = 0x1,
+    ber_type_tag_int = 0x2,
+    ber_type_tag_bit_str = 0x3,
+    ber_type_tag_oct_str = 0x4,
+    ber_type_tag_oct_null = 0x5,
+    ber_type_tag_oct_oid = 0x6,
+    ber_type_tag_seq = 0x10,
+    ber_type_tag_set = 0x11,
+};
+
+#define BER_CONSTRUCTED_MASK 0x20
+#define BER_SHORT_LEN_MASK 0x80
+
+static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
+{
+    return **data;
+}
+
+static int invoke_callback(BerDecodeCb cb, void *ctx,
+                           const uint8_t *value, size_t vlen)
+{
+    if (!cb) {
+        return 0;
+    }
+
+    return cb(ctx, value, vlen);
+}
+
+static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
+                           size_t nbytes)
+{
+    *data += nbytes;
+    *dlen -= nbytes;
+}
+
+static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
+{
+    uint8_t val = ber_peek_byte(data, dlen);
+
+    ber_cut_nbytes(data, dlen, 1);
+
+    return val;
+}
+
+static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
+                                     BerDecodeCb cb, void *ctx)
+{
+    const uint8_t *value;
+    size_t vlen = 0;
+    uint8_t byte_count = ber_cut_byte(data, dlen);
+
+    /* short format of definite-length */
+    if (!(byte_count & BER_SHORT_LEN_MASK)) {
+        if (byte_count > *dlen) {
+            return -1;
+        }
+
+        value = *data;
+        vlen = byte_count;
+        ber_cut_nbytes(data, dlen, vlen);
+
+        return invoke_callback(cb, ctx, value, vlen);
+    }
+
+    /* Ignore highest bit */
+    byte_count &= ~BER_SHORT_LEN_MASK;
+
+    /*
+     * size_t is enough to express the length, although the ber encoding
+     * standard supports larger length.
+     */
+    if (byte_count > sizeof(size_t)) {
+        return -1;
+    }
+
+    while (byte_count--) {
+        vlen <<= 8;
+        vlen += ber_cut_byte(data, dlen);
+    }
+
+    if (vlen > *dlen) {
+        return -1;
+    }
+
+    value = *data;
+    ber_cut_nbytes(data, dlen, vlen);
+
+    return invoke_callback(cb, ctx, value, vlen);
+}
+
+static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
+                                       BerDecodeCb cb, void *ctx)
+{
+    size_t vlen = 0;
+    const uint8_t *value;
+
+    if (*dlen < 3) {
+        return -1;
+    }
+
+    /* skip undefinite-length-mask 0x80 */
+    ber_cut_nbytes(data, dlen, 1);
+
+    value = *data;
+    while (vlen < *dlen) {
+        if ((*data)[vlen] != 0) {
+            vlen++;
+            continue;
+        }
+
+        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
+            ber_cut_nbytes(data, dlen, vlen + 2);
+            return invoke_callback(cb, ctx, value, vlen);
+        }
+
+        vlen += 2;
+    }
+
+    return -1;
+}
+
+static int ber_extract_data(const uint8_t **data, size_t *dlen,
+                            BerDecodeCb cb, void *ctx)
+{
+    uint8_t val = ber_peek_byte(data, dlen);
+
+    if (val == BER_SHORT_LEN_MASK) {
+        return ber_extract_undefinite_data(data, dlen, cb, ctx);
+    }
+
+    return ber_extract_definite_data(data, dlen, cb, ctx);
+}
+
+int ber_decode_int(const uint8_t **data, size_t *dlen,
+                   BerDecodeCb cb, void *ctx)
+{
+    uint8_t tag = ber_cut_byte(data, dlen);
+
+    /* INTEGER must encoded in primitive-form */
+    if (tag != ber_type_tag_int) {
+        return -1;
+    }
+
+    return ber_extract_data(data, dlen, cb, ctx);
+}
+
+int ber_decode_seq(const uint8_t **data, size_t *dlen,
+                   BerDecodeCb cb, void *ctx)
+{
+    uint8_t val = ber_cut_byte(data, dlen);
+
+    /* SEQUENCE must use constructed form */
+    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
+        return -1;
+    }
+
+    return ber_extract_data(data, dlen, cb, ctx);
+}
diff --git a/crypto/asn1_decoder.h b/crypto/asn1_decoder.h
new file mode 100644
index 0000000000..d33a7c81c4
--- /dev/null
+++ b/crypto/asn1_decoder.h
@@ -0,0 +1,42 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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
+
+/*
+ *  ctx: user content.
+ *  value: the starting address of |value| part of 'Tag-Length-Value' pattern.
+ *  vlen: length of the |value|.
+ */
+typedef int (*BerDecodeCb) (void *ctx, const uint8_t *value, size_t vlen);
+
+int ber_decode_int(const uint8_t **data,
+                   size_t *dlen,
+                   BerDecodeCb cb,
+                   void *ctx);
+
+int ber_decode_seq(const uint8_t **data,
+                   size_t *dlen,
+                   BerDecodeCb cb,
+                   void *ctx);
+
+#endif  /* QCRYPTO_ASN1_DECODER_H */
diff --git a/crypto/meson.build b/crypto/meson.build
index c32b57aeda..f398d7abda 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -27,6 +27,9 @@ if nettle.found()
   if xts == 'private'
     crypto_ss.add(files('xts.c'))
   endif
+  if hogweed.found()
+    crypto_ss.add(gmp, hogweed, files('akcipher-nettle.c', 'asn1_decoder.c'))
+  endif
 elif gcrypt.found()
   crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
 elif gnutls_crypto.found()
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index 03cc3bf46b..2ec7f0f8d7 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
 
 int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
 
+#ifdef CONFIG_HOGWEED
+QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key, size_t keylen,
+                                             void *para, Error **errp);
+#else
+static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
+                                             QCryptoAkcipherAlgorithm alg,
+                                             QCryptoAkcipherKeyType type,
+                                             const uint8_t *key, size_t keylen,
+                                             void *para, Error **errp)
+{
+    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
+    return NULL;
+}
+#endif
 
 #endif /* QCRYPTO_AKCIPHER_H */
diff --git a/meson.build b/meson.build
index 282e7c4650..ea6b8feb3c 100644
--- a/meson.build
+++ b/meson.build
@@ -1049,6 +1049,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()
@@ -1086,6 +1087,14 @@ 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
@@ -1567,6 +1576,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)
@@ -3614,6 +3624,7 @@ summary_info += {'libgcrypt':         gcrypt}
 summary_info += {'nettle':            nettle}
 if nettle.found()
    summary_info += {'  XTS':             xts != 'private'}
+   summary_info += {'  hogweed':         hogweed.found()}
 endif
 summary_info += {'AF_ALG support':    have_afalg}
 summary_info += {'rng-none':          get_option('rng_none')}
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 5/6] tests/crypto: Add test suite for crypto akcipher
  2022-03-23  2:49 ` zhenwei pi
  (?)
@ 2022-03-23  2:49   ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: jasowang, virtualization, qemu-devel, linux-crypto, herbert,
	Lei He, zhenwei pi

From: Lei He <helei.sig11@bytedance.com>

Add unit test and benchmark test for crypto akcipher.

Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 tests/bench/benchmark-crypto-akcipher.c | 163 ++++++
 tests/bench/meson.build                 |   6 +
 tests/bench/test_akcipher_keys.inc      | 277 +++++++++
 tests/unit/meson.build                  |   1 +
 tests/unit/test-crypto-akcipher.c       | 715 ++++++++++++++++++++++++
 5 files changed, 1162 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..152fed8d73
--- /dev/null
+++ b/tests/bench/benchmark-crypto-akcipher.c
@@ -0,0 +1,163 @@
+/*
+ * QEMU Crypto cipher speed benchmark
+ *
+ * Copyright (c) 2022 Bytedance
+ *
+ * Authors:
+ *    lei he <helei.sig11@bytedance.com>
+ *
+ * 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,
+                                            QCryptoRsaHashAlgorithm hash)
+{
+    QCryptoRsaOptions opt;
+    QCryptoAkcipher *rsa;
+    Error *err = NULL;
+
+    opt.padding_algo = padding;
+    opt.hash_algo = hash;
+    rsa = qcrypto_akcipher_new(QCRYPTO_AKCIPHER_ALG_RSA,
+                               QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+                               priv_key, keylen, &opt, &err);
+
+    g_assert(rsa != NULL);
+    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 40
+#define DURATION_SECONDS 10
+#define padding QCRYPTO_RSA_PADDING_ALG_PKCS1
+#define hash QCRYPTO_RSA_HASH_ALG_SHA1
+
+    Error *err = NULL;
+    QCryptoAkcipher *rsa;
+    uint8_t *dgst, *signature;
+    size_t count;
+
+    rsa = create_rsa_akcipher(priv_key, keylen, padding, hash);
+
+    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),
+                   QCryptoRsaHashAlgorithm_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, &err) > 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),
+                   QCryptoRsaHashAlgorithm_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),
+                   QCryptoRsaHashAlgorithm_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, &err) == 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),
+                   QCryptoRsaHashAlgorithm_str(hash),
+                   count, g_test_timer_last(),
+                   (double)count / g_test_timer_last());
+
+    g_assert(qcrypto_akcipher_free(rsa, &err) == 0);
+    g_free(dgst);
+    g_free(signature);
+}
+
+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..92491538f9 100644
--- a/tests/bench/meson.build
+++ b/tests/bench/meson.build
@@ -23,6 +23,12 @@ if have_block
   }
 endif
 
+if nettle.found() and hogweed.found()
+    benchs += {
+        'benchmark-crypto-akcipher': [crypto],
+    }
+endif
+
 foreach bench_name, deps: benchs
   exe = executable(bench_name, bench_name + '.c',
                    dependencies: [qemuutil] + deps)
diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc
new file mode 100644
index 0000000000..6c291b9542
--- /dev/null
+++ b/tests/bench/test_akcipher_keys.inc
@@ -0,0 +1,277 @@
+/*
+ * 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 <helei.sig11@bytedance.com>
+ */
+
+/* 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 96b295263e..4ff2fef30f 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -77,6 +77,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..5efb71f61f
--- /dev/null
+++ b/tests/unit/test-crypto-akcipher.c
@@ -0,0 +1,715 @@
+/*
+ * QEMU Crypto cipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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[] = {
+    0x07, 0x1a, 0xa2, 0x05, 0x7b, 0xe4, 0x68, 0x0f,
+    0xc3, 0x27, 0xc4, 0xd1, 0xa8, 0x1c, 0x44, 0xf0,
+    0x40, 0x9c, 0xb4, 0xaa, 0xb4, 0xcf, 0x6f, 0x9a,
+    0x01, 0xe5, 0xa1, 0x60, 0xe9, 0x1e, 0x1e, 0x5c,
+    0x3a, 0x55, 0xaa, 0xea, 0xc0, 0xf9, 0xb7, 0x84 };
+
+static const uint8_t exp_signature_rsa2048_pkcs1[] = {
+    0x62, 0x25, 0xe1, 0x30, 0x7d, 0x39, 0x7b, 0x9c,
+    0x50, 0xf6, 0x74, 0x4e, 0xb9, 0x3c, 0xbe, 0x6e,
+    0x48, 0xf2, 0x61, 0x19, 0x56, 0x85, 0x7f, 0x3e,
+    0x27, 0xff, 0x27, 0xe8, 0xec, 0x68, 0x4e, 0x7a,
+    0x87, 0x37, 0xda, 0x5a, 0x32, 0x4e, 0x67, 0xc9,
+    0x57, 0xda, 0xf1, 0xe4, 0x9d, 0x59, 0x5c, 0x8e,
+    0x89, 0x58, 0x52, 0xe2, 0xb2, 0xda, 0xc8, 0x48,
+    0xbe, 0x5e, 0x22, 0x59, 0xe0, 0x92, 0xf8, 0x42,
+    0x63, 0x66, 0x88, 0xa7, 0xfe, 0x04, 0x7c, 0x07,
+    0x0a, 0x5d, 0xa2, 0x1e, 0x05, 0xb0, 0xf7, 0x55,
+    0xea, 0x54, 0xd7, 0x64, 0xed, 0x4f, 0x39, 0x0a,
+    0x33, 0x07, 0x85, 0xae, 0x5c, 0x5f, 0xd0, 0x3e,
+    0x04, 0x06, 0xe9, 0x19, 0x7a, 0x10, 0x20, 0x34,
+    0x85, 0x04, 0x0c, 0x43, 0x4d, 0x72, 0xfa, 0x66,
+    0xcc, 0x68, 0xf8, 0x16, 0x3f, 0x04, 0x8d, 0x38,
+    0x3c, 0xbc, 0x6d, 0x0a, 0x4c, 0x31, 0xe3, 0x13,
+    0x71, 0x73, 0x97, 0x09, 0x23, 0x2e, 0xcc, 0x93,
+    0x0c, 0xa5, 0xa7, 0x3f, 0x7e, 0xe8, 0x84, 0x57,
+    0x26, 0x32, 0x85, 0xb2, 0x1e, 0x44, 0x0f, 0xf0,
+    0x1b, 0xe2, 0x23, 0x4b, 0x58, 0x75, 0x06, 0xfe,
+    0xf7, 0x77, 0x85, 0x54, 0xf0, 0xcd, 0x93, 0x48,
+    0x80, 0x71, 0xd2, 0xc6, 0x19, 0xcc, 0x9b, 0x9b,
+    0xa8, 0x59, 0x6f, 0x16, 0x69, 0x9b, 0x7b, 0x9e,
+    0xa9, 0xb6, 0x3a, 0xcf, 0x00, 0x1f, 0xd9, 0x9a,
+    0x40, 0xd6, 0x20, 0xc0, 0x9a, 0x45, 0xc5, 0xd9,
+    0x00, 0x91, 0x1e, 0x9d, 0x49, 0x5d, 0x5b, 0x56,
+    0xd6, 0x56, 0x25, 0xdb, 0x89, 0x3c, 0x8f, 0x6f,
+    0x2a, 0x68, 0x7f, 0xca, 0x55, 0xf6, 0x63, 0x14,
+    0x53, 0x28, 0xa2, 0xca, 0xfd, 0x53, 0x85, 0xfd,
+    0x54, 0xcd, 0xdf, 0x74, 0x87, 0xb1, 0x54, 0x1c,
+    0xb3, 0x24, 0x01, 0xfb, 0x2e, 0x4e, 0x56, 0xc6,
+    0xf9, 0x9b, 0x9d, 0xf1, 0x03, 0xa3, 0x05, 0x39,
+};
+
+static const uint8_t exp_signature_rsa1024_pkcs1[] = {
+    0xd7, 0x9b, 0x45, 0x27, 0xff, 0xa0, 0x3c, 0x8b,
+    0xfa, 0x65, 0x84, 0x05, 0x06, 0xa0, 0xd9, 0x67,
+    0xd0, 0x28, 0x77, 0x5f, 0xfb, 0xd6, 0xc8, 0xe8,
+    0xce, 0x7e, 0x4f, 0x30, 0x01, 0xf7, 0xa0, 0xd3,
+    0xbd, 0x3c, 0x53, 0xe6, 0x1c, 0xf1, 0x98, 0xa2,
+    0x7d, 0xf7, 0xf8, 0x72, 0xc0, 0x97, 0x5d, 0xc0,
+    0xaa, 0xf2, 0xf0, 0x11, 0x23, 0x3a, 0x77, 0x14,
+    0xab, 0x37, 0x47, 0x45, 0x2a, 0x8d, 0xde, 0xb3,
+    0xa2, 0x0a, 0x29, 0x58, 0x93, 0xe0, 0x28, 0xcd,
+    0x9d, 0xa2, 0x3d, 0x21, 0x9b, 0x73, 0xbc, 0x9b,
+    0x3d, 0xd6, 0x27, 0x89, 0xa7, 0x89, 0x0c, 0x82,
+    0x08, 0x4d, 0x2d, 0x69, 0x9d, 0x5f, 0xe5, 0xdf,
+    0x08, 0xc9, 0xe9, 0xe9, 0x57, 0xf6, 0xe5, 0xc1,
+    0x97, 0x6a, 0x4b, 0xbb, 0xf2, 0x59, 0x7b, 0xc4,
+    0xf0, 0xef, 0xc9, 0x4c, 0xf1, 0x34, 0x49, 0xef,
+    0xe4, 0x14, 0xe7, 0x28, 0x6c, 0xc4, 0xba, 0x7c,
+};
+
+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;
+    QCryptoAkcipherAlgorithm alg;
+
+    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;
+
+    union {
+        QCryptoRsaOptions rsa;
+        QCryptoEcdsaOptions ecdsa;
+    } opt;
+};
+
+#define Byte 8
+static QCryptoAkcipherTestData test_data[] = {
+    /* rsa1024 with raw padding */
+    {
+        .path = "/crypto/akcipher/rsa1024-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 = 1024 / Byte,
+        .ciphertext = exp_ciphertext_rsa1024_raw,
+        .clen = sizeof(exp_ciphertext_rsa1024_raw),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
+            },
+        }
+    },
+
+    /* rsa1024 with pkcs1 padding */
+    {
+        .path = "/crypto/akcipher/rsa1024-pkcs1",
+        .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 = 1024 / Byte / 2,
+        .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),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
+            },
+        }
+    },
+
+    /* rsa2048 with raw padding */
+    {
+        .path = "/crypto/akcipher/rsa2048-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 = 2048 / Byte,
+        .ciphertext = exp_ciphertext_rsa2048_raw,
+        .clen = sizeof(exp_ciphertext_rsa2048_raw),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
+            },
+        }
+    },
+
+    /* rsa2048 with pkcs1 padding */
+    {
+        .path = "/crypto/akcipher/rsa2048-pkcs1",
+        .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 = 2048 / Byte / 2,
+        .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),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
+            },
+        }
+    },
+
+};
+
+static void test_akcipher(const void *opaque)
+{
+    const QCryptoAkcipherTestData *data = opaque;
+    Error *err = NULL;
+    uint8_t *plaintext = NULL, *ciphertext = NULL, *signature = NULL;
+    QCryptoAkcipher *pub_key, *priv_key;
+
+    pub_key = qcrypto_akcipher_new(data->alg,
+                                   QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+                                   data->pub_key, data->pub_key_len,
+                                   (void *)&data->opt, &err);
+    g_assert(pub_key != NULL);
+    priv_key = qcrypto_akcipher_new(data->alg,
+                                    QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+                                    data->priv_key, data->priv_key_len,
+                                    (void *)&data->opt, &err);
+    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, &err) > 0);
+        g_assert(err == NULL);
+
+        /**
+         * 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, &err) == data->plen);
+        g_assert(err == NULL);
+        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, &err) > 0);
+        /**
+         * The signature generated each time may be different, here only check
+         * the verification.
+         */
+        g_assert(err == NULL);
+
+        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+                                         data->dgst, data->dlen, &err) == 0);
+        g_assert(err == NULL);
+        ++signature[0];
+        /* Here error should be ignored */
+        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+                                         data->dgst, data->dlen, NULL) != 0);
+    }
+
+    g_free(plaintext);
+    g_free(ciphertext);
+    g_free(signature);
+    g_assert(qcrypto_akcipher_free(pub_key, &err) == 0);
+    g_assert(err == NULL);
+    g_assert(qcrypto_akcipher_free(priv_key, &err) == 0);
+    g_assert(err == NULL);
+}
+
+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.25.1


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 5/6] tests/crypto: Add test suite for crypto akcipher
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, qemu-devel, zhenwei pi, virtualization, linux-crypto, Lei He

From: Lei He <helei.sig11@bytedance.com>

Add unit test and benchmark test for crypto akcipher.

Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 tests/bench/benchmark-crypto-akcipher.c | 163 ++++++
 tests/bench/meson.build                 |   6 +
 tests/bench/test_akcipher_keys.inc      | 277 +++++++++
 tests/unit/meson.build                  |   1 +
 tests/unit/test-crypto-akcipher.c       | 715 ++++++++++++++++++++++++
 5 files changed, 1162 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..152fed8d73
--- /dev/null
+++ b/tests/bench/benchmark-crypto-akcipher.c
@@ -0,0 +1,163 @@
+/*
+ * QEMU Crypto cipher speed benchmark
+ *
+ * Copyright (c) 2022 Bytedance
+ *
+ * Authors:
+ *    lei he <helei.sig11@bytedance.com>
+ *
+ * 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,
+                                            QCryptoRsaHashAlgorithm hash)
+{
+    QCryptoRsaOptions opt;
+    QCryptoAkcipher *rsa;
+    Error *err = NULL;
+
+    opt.padding_algo = padding;
+    opt.hash_algo = hash;
+    rsa = qcrypto_akcipher_new(QCRYPTO_AKCIPHER_ALG_RSA,
+                               QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+                               priv_key, keylen, &opt, &err);
+
+    g_assert(rsa != NULL);
+    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 40
+#define DURATION_SECONDS 10
+#define padding QCRYPTO_RSA_PADDING_ALG_PKCS1
+#define hash QCRYPTO_RSA_HASH_ALG_SHA1
+
+    Error *err = NULL;
+    QCryptoAkcipher *rsa;
+    uint8_t *dgst, *signature;
+    size_t count;
+
+    rsa = create_rsa_akcipher(priv_key, keylen, padding, hash);
+
+    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),
+                   QCryptoRsaHashAlgorithm_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, &err) > 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),
+                   QCryptoRsaHashAlgorithm_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),
+                   QCryptoRsaHashAlgorithm_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, &err) == 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),
+                   QCryptoRsaHashAlgorithm_str(hash),
+                   count, g_test_timer_last(),
+                   (double)count / g_test_timer_last());
+
+    g_assert(qcrypto_akcipher_free(rsa, &err) == 0);
+    g_free(dgst);
+    g_free(signature);
+}
+
+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..92491538f9 100644
--- a/tests/bench/meson.build
+++ b/tests/bench/meson.build
@@ -23,6 +23,12 @@ if have_block
   }
 endif
 
+if nettle.found() and hogweed.found()
+    benchs += {
+        'benchmark-crypto-akcipher': [crypto],
+    }
+endif
+
 foreach bench_name, deps: benchs
   exe = executable(bench_name, bench_name + '.c',
                    dependencies: [qemuutil] + deps)
diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc
new file mode 100644
index 0000000000..6c291b9542
--- /dev/null
+++ b/tests/bench/test_akcipher_keys.inc
@@ -0,0 +1,277 @@
+/*
+ * 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 <helei.sig11@bytedance.com>
+ */
+
+/* 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 96b295263e..4ff2fef30f 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -77,6 +77,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..5efb71f61f
--- /dev/null
+++ b/tests/unit/test-crypto-akcipher.c
@@ -0,0 +1,715 @@
+/*
+ * QEMU Crypto cipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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[] = {
+    0x07, 0x1a, 0xa2, 0x05, 0x7b, 0xe4, 0x68, 0x0f,
+    0xc3, 0x27, 0xc4, 0xd1, 0xa8, 0x1c, 0x44, 0xf0,
+    0x40, 0x9c, 0xb4, 0xaa, 0xb4, 0xcf, 0x6f, 0x9a,
+    0x01, 0xe5, 0xa1, 0x60, 0xe9, 0x1e, 0x1e, 0x5c,
+    0x3a, 0x55, 0xaa, 0xea, 0xc0, 0xf9, 0xb7, 0x84 };
+
+static const uint8_t exp_signature_rsa2048_pkcs1[] = {
+    0x62, 0x25, 0xe1, 0x30, 0x7d, 0x39, 0x7b, 0x9c,
+    0x50, 0xf6, 0x74, 0x4e, 0xb9, 0x3c, 0xbe, 0x6e,
+    0x48, 0xf2, 0x61, 0x19, 0x56, 0x85, 0x7f, 0x3e,
+    0x27, 0xff, 0x27, 0xe8, 0xec, 0x68, 0x4e, 0x7a,
+    0x87, 0x37, 0xda, 0x5a, 0x32, 0x4e, 0x67, 0xc9,
+    0x57, 0xda, 0xf1, 0xe4, 0x9d, 0x59, 0x5c, 0x8e,
+    0x89, 0x58, 0x52, 0xe2, 0xb2, 0xda, 0xc8, 0x48,
+    0xbe, 0x5e, 0x22, 0x59, 0xe0, 0x92, 0xf8, 0x42,
+    0x63, 0x66, 0x88, 0xa7, 0xfe, 0x04, 0x7c, 0x07,
+    0x0a, 0x5d, 0xa2, 0x1e, 0x05, 0xb0, 0xf7, 0x55,
+    0xea, 0x54, 0xd7, 0x64, 0xed, 0x4f, 0x39, 0x0a,
+    0x33, 0x07, 0x85, 0xae, 0x5c, 0x5f, 0xd0, 0x3e,
+    0x04, 0x06, 0xe9, 0x19, 0x7a, 0x10, 0x20, 0x34,
+    0x85, 0x04, 0x0c, 0x43, 0x4d, 0x72, 0xfa, 0x66,
+    0xcc, 0x68, 0xf8, 0x16, 0x3f, 0x04, 0x8d, 0x38,
+    0x3c, 0xbc, 0x6d, 0x0a, 0x4c, 0x31, 0xe3, 0x13,
+    0x71, 0x73, 0x97, 0x09, 0x23, 0x2e, 0xcc, 0x93,
+    0x0c, 0xa5, 0xa7, 0x3f, 0x7e, 0xe8, 0x84, 0x57,
+    0x26, 0x32, 0x85, 0xb2, 0x1e, 0x44, 0x0f, 0xf0,
+    0x1b, 0xe2, 0x23, 0x4b, 0x58, 0x75, 0x06, 0xfe,
+    0xf7, 0x77, 0x85, 0x54, 0xf0, 0xcd, 0x93, 0x48,
+    0x80, 0x71, 0xd2, 0xc6, 0x19, 0xcc, 0x9b, 0x9b,
+    0xa8, 0x59, 0x6f, 0x16, 0x69, 0x9b, 0x7b, 0x9e,
+    0xa9, 0xb6, 0x3a, 0xcf, 0x00, 0x1f, 0xd9, 0x9a,
+    0x40, 0xd6, 0x20, 0xc0, 0x9a, 0x45, 0xc5, 0xd9,
+    0x00, 0x91, 0x1e, 0x9d, 0x49, 0x5d, 0x5b, 0x56,
+    0xd6, 0x56, 0x25, 0xdb, 0x89, 0x3c, 0x8f, 0x6f,
+    0x2a, 0x68, 0x7f, 0xca, 0x55, 0xf6, 0x63, 0x14,
+    0x53, 0x28, 0xa2, 0xca, 0xfd, 0x53, 0x85, 0xfd,
+    0x54, 0xcd, 0xdf, 0x74, 0x87, 0xb1, 0x54, 0x1c,
+    0xb3, 0x24, 0x01, 0xfb, 0x2e, 0x4e, 0x56, 0xc6,
+    0xf9, 0x9b, 0x9d, 0xf1, 0x03, 0xa3, 0x05, 0x39,
+};
+
+static const uint8_t exp_signature_rsa1024_pkcs1[] = {
+    0xd7, 0x9b, 0x45, 0x27, 0xff, 0xa0, 0x3c, 0x8b,
+    0xfa, 0x65, 0x84, 0x05, 0x06, 0xa0, 0xd9, 0x67,
+    0xd0, 0x28, 0x77, 0x5f, 0xfb, 0xd6, 0xc8, 0xe8,
+    0xce, 0x7e, 0x4f, 0x30, 0x01, 0xf7, 0xa0, 0xd3,
+    0xbd, 0x3c, 0x53, 0xe6, 0x1c, 0xf1, 0x98, 0xa2,
+    0x7d, 0xf7, 0xf8, 0x72, 0xc0, 0x97, 0x5d, 0xc0,
+    0xaa, 0xf2, 0xf0, 0x11, 0x23, 0x3a, 0x77, 0x14,
+    0xab, 0x37, 0x47, 0x45, 0x2a, 0x8d, 0xde, 0xb3,
+    0xa2, 0x0a, 0x29, 0x58, 0x93, 0xe0, 0x28, 0xcd,
+    0x9d, 0xa2, 0x3d, 0x21, 0x9b, 0x73, 0xbc, 0x9b,
+    0x3d, 0xd6, 0x27, 0x89, 0xa7, 0x89, 0x0c, 0x82,
+    0x08, 0x4d, 0x2d, 0x69, 0x9d, 0x5f, 0xe5, 0xdf,
+    0x08, 0xc9, 0xe9, 0xe9, 0x57, 0xf6, 0xe5, 0xc1,
+    0x97, 0x6a, 0x4b, 0xbb, 0xf2, 0x59, 0x7b, 0xc4,
+    0xf0, 0xef, 0xc9, 0x4c, 0xf1, 0x34, 0x49, 0xef,
+    0xe4, 0x14, 0xe7, 0x28, 0x6c, 0xc4, 0xba, 0x7c,
+};
+
+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;
+    QCryptoAkcipherAlgorithm alg;
+
+    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;
+
+    union {
+        QCryptoRsaOptions rsa;
+        QCryptoEcdsaOptions ecdsa;
+    } opt;
+};
+
+#define Byte 8
+static QCryptoAkcipherTestData test_data[] = {
+    /* rsa1024 with raw padding */
+    {
+        .path = "/crypto/akcipher/rsa1024-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 = 1024 / Byte,
+        .ciphertext = exp_ciphertext_rsa1024_raw,
+        .clen = sizeof(exp_ciphertext_rsa1024_raw),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
+            },
+        }
+    },
+
+    /* rsa1024 with pkcs1 padding */
+    {
+        .path = "/crypto/akcipher/rsa1024-pkcs1",
+        .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 = 1024 / Byte / 2,
+        .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),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
+            },
+        }
+    },
+
+    /* rsa2048 with raw padding */
+    {
+        .path = "/crypto/akcipher/rsa2048-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 = 2048 / Byte,
+        .ciphertext = exp_ciphertext_rsa2048_raw,
+        .clen = sizeof(exp_ciphertext_rsa2048_raw),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
+            },
+        }
+    },
+
+    /* rsa2048 with pkcs1 padding */
+    {
+        .path = "/crypto/akcipher/rsa2048-pkcs1",
+        .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 = 2048 / Byte / 2,
+        .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),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
+            },
+        }
+    },
+
+};
+
+static void test_akcipher(const void *opaque)
+{
+    const QCryptoAkcipherTestData *data = opaque;
+    Error *err = NULL;
+    uint8_t *plaintext = NULL, *ciphertext = NULL, *signature = NULL;
+    QCryptoAkcipher *pub_key, *priv_key;
+
+    pub_key = qcrypto_akcipher_new(data->alg,
+                                   QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+                                   data->pub_key, data->pub_key_len,
+                                   (void *)&data->opt, &err);
+    g_assert(pub_key != NULL);
+    priv_key = qcrypto_akcipher_new(data->alg,
+                                    QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+                                    data->priv_key, data->priv_key_len,
+                                    (void *)&data->opt, &err);
+    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, &err) > 0);
+        g_assert(err == NULL);
+
+        /**
+         * 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, &err) == data->plen);
+        g_assert(err == NULL);
+        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, &err) > 0);
+        /**
+         * The signature generated each time may be different, here only check
+         * the verification.
+         */
+        g_assert(err == NULL);
+
+        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+                                         data->dgst, data->dlen, &err) == 0);
+        g_assert(err == NULL);
+        ++signature[0];
+        /* Here error should be ignored */
+        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+                                         data->dgst, data->dlen, NULL) != 0);
+    }
+
+    g_free(plaintext);
+    g_free(ciphertext);
+    g_free(signature);
+    g_assert(qcrypto_akcipher_free(pub_key, &err) == 0);
+    g_assert(err == NULL);
+    g_assert(qcrypto_akcipher_free(priv_key, &err) == 0);
+    g_assert(err == NULL);
+}
+
+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.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 5/6] tests/crypto: Add test suite for crypto akcipher
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, jasowang, qemu-devel, zhenwei pi, virtualization,
	linux-crypto, Lei He

From: Lei He <helei.sig11@bytedance.com>

Add unit test and benchmark test for crypto akcipher.

Signed-off-by: lei he <helei.sig11@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 tests/bench/benchmark-crypto-akcipher.c | 163 ++++++
 tests/bench/meson.build                 |   6 +
 tests/bench/test_akcipher_keys.inc      | 277 +++++++++
 tests/unit/meson.build                  |   1 +
 tests/unit/test-crypto-akcipher.c       | 715 ++++++++++++++++++++++++
 5 files changed, 1162 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..152fed8d73
--- /dev/null
+++ b/tests/bench/benchmark-crypto-akcipher.c
@@ -0,0 +1,163 @@
+/*
+ * QEMU Crypto cipher speed benchmark
+ *
+ * Copyright (c) 2022 Bytedance
+ *
+ * Authors:
+ *    lei he <helei.sig11@bytedance.com>
+ *
+ * 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,
+                                            QCryptoRsaHashAlgorithm hash)
+{
+    QCryptoRsaOptions opt;
+    QCryptoAkcipher *rsa;
+    Error *err = NULL;
+
+    opt.padding_algo = padding;
+    opt.hash_algo = hash;
+    rsa = qcrypto_akcipher_new(QCRYPTO_AKCIPHER_ALG_RSA,
+                               QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+                               priv_key, keylen, &opt, &err);
+
+    g_assert(rsa != NULL);
+    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 40
+#define DURATION_SECONDS 10
+#define padding QCRYPTO_RSA_PADDING_ALG_PKCS1
+#define hash QCRYPTO_RSA_HASH_ALG_SHA1
+
+    Error *err = NULL;
+    QCryptoAkcipher *rsa;
+    uint8_t *dgst, *signature;
+    size_t count;
+
+    rsa = create_rsa_akcipher(priv_key, keylen, padding, hash);
+
+    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),
+                   QCryptoRsaHashAlgorithm_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, &err) > 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),
+                   QCryptoRsaHashAlgorithm_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),
+                   QCryptoRsaHashAlgorithm_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, &err) == 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),
+                   QCryptoRsaHashAlgorithm_str(hash),
+                   count, g_test_timer_last(),
+                   (double)count / g_test_timer_last());
+
+    g_assert(qcrypto_akcipher_free(rsa, &err) == 0);
+    g_free(dgst);
+    g_free(signature);
+}
+
+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..92491538f9 100644
--- a/tests/bench/meson.build
+++ b/tests/bench/meson.build
@@ -23,6 +23,12 @@ if have_block
   }
 endif
 
+if nettle.found() and hogweed.found()
+    benchs += {
+        'benchmark-crypto-akcipher': [crypto],
+    }
+endif
+
 foreach bench_name, deps: benchs
   exe = executable(bench_name, bench_name + '.c',
                    dependencies: [qemuutil] + deps)
diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc
new file mode 100644
index 0000000000..6c291b9542
--- /dev/null
+++ b/tests/bench/test_akcipher_keys.inc
@@ -0,0 +1,277 @@
+/*
+ * 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 <helei.sig11@bytedance.com>
+ */
+
+/* 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 96b295263e..4ff2fef30f 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -77,6 +77,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..5efb71f61f
--- /dev/null
+++ b/tests/unit/test-crypto-akcipher.c
@@ -0,0 +1,715 @@
+/*
+ * QEMU Crypto cipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he <helei.sig11@bytedance.com>
+ *
+ * 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[] = {
+    0x07, 0x1a, 0xa2, 0x05, 0x7b, 0xe4, 0x68, 0x0f,
+    0xc3, 0x27, 0xc4, 0xd1, 0xa8, 0x1c, 0x44, 0xf0,
+    0x40, 0x9c, 0xb4, 0xaa, 0xb4, 0xcf, 0x6f, 0x9a,
+    0x01, 0xe5, 0xa1, 0x60, 0xe9, 0x1e, 0x1e, 0x5c,
+    0x3a, 0x55, 0xaa, 0xea, 0xc0, 0xf9, 0xb7, 0x84 };
+
+static const uint8_t exp_signature_rsa2048_pkcs1[] = {
+    0x62, 0x25, 0xe1, 0x30, 0x7d, 0x39, 0x7b, 0x9c,
+    0x50, 0xf6, 0x74, 0x4e, 0xb9, 0x3c, 0xbe, 0x6e,
+    0x48, 0xf2, 0x61, 0x19, 0x56, 0x85, 0x7f, 0x3e,
+    0x27, 0xff, 0x27, 0xe8, 0xec, 0x68, 0x4e, 0x7a,
+    0x87, 0x37, 0xda, 0x5a, 0x32, 0x4e, 0x67, 0xc9,
+    0x57, 0xda, 0xf1, 0xe4, 0x9d, 0x59, 0x5c, 0x8e,
+    0x89, 0x58, 0x52, 0xe2, 0xb2, 0xda, 0xc8, 0x48,
+    0xbe, 0x5e, 0x22, 0x59, 0xe0, 0x92, 0xf8, 0x42,
+    0x63, 0x66, 0x88, 0xa7, 0xfe, 0x04, 0x7c, 0x07,
+    0x0a, 0x5d, 0xa2, 0x1e, 0x05, 0xb0, 0xf7, 0x55,
+    0xea, 0x54, 0xd7, 0x64, 0xed, 0x4f, 0x39, 0x0a,
+    0x33, 0x07, 0x85, 0xae, 0x5c, 0x5f, 0xd0, 0x3e,
+    0x04, 0x06, 0xe9, 0x19, 0x7a, 0x10, 0x20, 0x34,
+    0x85, 0x04, 0x0c, 0x43, 0x4d, 0x72, 0xfa, 0x66,
+    0xcc, 0x68, 0xf8, 0x16, 0x3f, 0x04, 0x8d, 0x38,
+    0x3c, 0xbc, 0x6d, 0x0a, 0x4c, 0x31, 0xe3, 0x13,
+    0x71, 0x73, 0x97, 0x09, 0x23, 0x2e, 0xcc, 0x93,
+    0x0c, 0xa5, 0xa7, 0x3f, 0x7e, 0xe8, 0x84, 0x57,
+    0x26, 0x32, 0x85, 0xb2, 0x1e, 0x44, 0x0f, 0xf0,
+    0x1b, 0xe2, 0x23, 0x4b, 0x58, 0x75, 0x06, 0xfe,
+    0xf7, 0x77, 0x85, 0x54, 0xf0, 0xcd, 0x93, 0x48,
+    0x80, 0x71, 0xd2, 0xc6, 0x19, 0xcc, 0x9b, 0x9b,
+    0xa8, 0x59, 0x6f, 0x16, 0x69, 0x9b, 0x7b, 0x9e,
+    0xa9, 0xb6, 0x3a, 0xcf, 0x00, 0x1f, 0xd9, 0x9a,
+    0x40, 0xd6, 0x20, 0xc0, 0x9a, 0x45, 0xc5, 0xd9,
+    0x00, 0x91, 0x1e, 0x9d, 0x49, 0x5d, 0x5b, 0x56,
+    0xd6, 0x56, 0x25, 0xdb, 0x89, 0x3c, 0x8f, 0x6f,
+    0x2a, 0x68, 0x7f, 0xca, 0x55, 0xf6, 0x63, 0x14,
+    0x53, 0x28, 0xa2, 0xca, 0xfd, 0x53, 0x85, 0xfd,
+    0x54, 0xcd, 0xdf, 0x74, 0x87, 0xb1, 0x54, 0x1c,
+    0xb3, 0x24, 0x01, 0xfb, 0x2e, 0x4e, 0x56, 0xc6,
+    0xf9, 0x9b, 0x9d, 0xf1, 0x03, 0xa3, 0x05, 0x39,
+};
+
+static const uint8_t exp_signature_rsa1024_pkcs1[] = {
+    0xd7, 0x9b, 0x45, 0x27, 0xff, 0xa0, 0x3c, 0x8b,
+    0xfa, 0x65, 0x84, 0x05, 0x06, 0xa0, 0xd9, 0x67,
+    0xd0, 0x28, 0x77, 0x5f, 0xfb, 0xd6, 0xc8, 0xe8,
+    0xce, 0x7e, 0x4f, 0x30, 0x01, 0xf7, 0xa0, 0xd3,
+    0xbd, 0x3c, 0x53, 0xe6, 0x1c, 0xf1, 0x98, 0xa2,
+    0x7d, 0xf7, 0xf8, 0x72, 0xc0, 0x97, 0x5d, 0xc0,
+    0xaa, 0xf2, 0xf0, 0x11, 0x23, 0x3a, 0x77, 0x14,
+    0xab, 0x37, 0x47, 0x45, 0x2a, 0x8d, 0xde, 0xb3,
+    0xa2, 0x0a, 0x29, 0x58, 0x93, 0xe0, 0x28, 0xcd,
+    0x9d, 0xa2, 0x3d, 0x21, 0x9b, 0x73, 0xbc, 0x9b,
+    0x3d, 0xd6, 0x27, 0x89, 0xa7, 0x89, 0x0c, 0x82,
+    0x08, 0x4d, 0x2d, 0x69, 0x9d, 0x5f, 0xe5, 0xdf,
+    0x08, 0xc9, 0xe9, 0xe9, 0x57, 0xf6, 0xe5, 0xc1,
+    0x97, 0x6a, 0x4b, 0xbb, 0xf2, 0x59, 0x7b, 0xc4,
+    0xf0, 0xef, 0xc9, 0x4c, 0xf1, 0x34, 0x49, 0xef,
+    0xe4, 0x14, 0xe7, 0x28, 0x6c, 0xc4, 0xba, 0x7c,
+};
+
+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;
+    QCryptoAkcipherAlgorithm alg;
+
+    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;
+
+    union {
+        QCryptoRsaOptions rsa;
+        QCryptoEcdsaOptions ecdsa;
+    } opt;
+};
+
+#define Byte 8
+static QCryptoAkcipherTestData test_data[] = {
+    /* rsa1024 with raw padding */
+    {
+        .path = "/crypto/akcipher/rsa1024-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 = 1024 / Byte,
+        .ciphertext = exp_ciphertext_rsa1024_raw,
+        .clen = sizeof(exp_ciphertext_rsa1024_raw),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
+            },
+        }
+    },
+
+    /* rsa1024 with pkcs1 padding */
+    {
+        .path = "/crypto/akcipher/rsa1024-pkcs1",
+        .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 = 1024 / Byte / 2,
+        .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),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
+            },
+        }
+    },
+
+    /* rsa2048 with raw padding */
+    {
+        .path = "/crypto/akcipher/rsa2048-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 = 2048 / Byte,
+        .ciphertext = exp_ciphertext_rsa2048_raw,
+        .clen = sizeof(exp_ciphertext_rsa2048_raw),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
+            },
+        }
+    },
+
+    /* rsa2048 with pkcs1 padding */
+    {
+        .path = "/crypto/akcipher/rsa2048-pkcs1",
+        .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 = 2048 / Byte / 2,
+        .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),
+
+        .opt = {
+            .rsa = {
+                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
+                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
+            },
+        }
+    },
+
+};
+
+static void test_akcipher(const void *opaque)
+{
+    const QCryptoAkcipherTestData *data = opaque;
+    Error *err = NULL;
+    uint8_t *plaintext = NULL, *ciphertext = NULL, *signature = NULL;
+    QCryptoAkcipher *pub_key, *priv_key;
+
+    pub_key = qcrypto_akcipher_new(data->alg,
+                                   QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+                                   data->pub_key, data->pub_key_len,
+                                   (void *)&data->opt, &err);
+    g_assert(pub_key != NULL);
+    priv_key = qcrypto_akcipher_new(data->alg,
+                                    QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+                                    data->priv_key, data->priv_key_len,
+                                    (void *)&data->opt, &err);
+    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, &err) > 0);
+        g_assert(err == NULL);
+
+        /**
+         * 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, &err) == data->plen);
+        g_assert(err == NULL);
+        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, &err) > 0);
+        /**
+         * The signature generated each time may be different, here only check
+         * the verification.
+         */
+        g_assert(err == NULL);
+
+        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+                                         data->dgst, data->dlen, &err) == 0);
+        g_assert(err == NULL);
+        ++signature[0];
+        /* Here error should be ignored */
+        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
+                                         data->dgst, data->dlen, NULL) != 0);
+    }
+
+    g_free(plaintext);
+    g_free(ciphertext);
+    g_free(signature);
+    g_assert(qcrypto_akcipher_free(pub_key, &err) == 0);
+    g_assert(err == NULL);
+    g_assert(qcrypto_akcipher_free(priv_key, &err) == 0);
+    g_assert(err == NULL);
+}
+
+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.25.1



^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 6/6] virtio-crypto: Introduce RSA algorithm
  2022-03-23  2:49 ` zhenwei pi
  (?)
@ 2022-03-23  2:49   ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, qemu-devel, zhenwei pi, virtualization, linux-crypto

There are two parts in this patch:
1, support akcipher service by cryptodev-builtin driver
2, virtio-crypto driver supports akcipher service

Then virtio-crypto gets request from guest side, and forwards the
request to builtin driver to handle it.

Test with a guest linux:
1, The self-test framework of crypto layer works fine in guest kernel
2, Test with Linux guest(with asym support), the following script
test(note that pkey_XXX is supported only in a newer version of keyutils):
  - both public key & private key
  - create/close session
  - encrypt/decrypt/sign/verify basic driver operation
  - also test with kernel crypto layer(pkey add/query)

All the cases work fine.

Run script in guest:
rm -rf *.der *.pem *.pfx
modprobe pkcs8_key_parser # if CONFIG_PKCS8_PRIVATE_KEY_PARSER=m
rm -rf /tmp/data
dd if=/dev/random of=/tmp/data count=1 bs=226

openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -subj "/C=CN/ST=BJ/L=HD/O=qemu/OU=dev/CN=qemu/emailAddress=qemu@qemu.org"
openssl pkcs8 -in key.pem -topk8 -nocrypt -outform DER -out key.der
openssl x509 -in cert.pem -inform PEM -outform DER -out cert.der

PRIV_KEY_ID=`cat key.der | keyctl padd asymmetric test_priv_key @s`
echo "priv key id = "$PRIV_KEY_ID
PUB_KEY_ID=`cat cert.der | keyctl padd asymmetric test_pub_key @s`
echo "pub key id = "$PUB_KEY_ID

keyctl pkey_query $PRIV_KEY_ID 0
keyctl pkey_query $PUB_KEY_ID 0

echo "Enc with priv key..."
keyctl pkey_encrypt $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.priv
echo "Dec with pub key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.priv enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Sign with priv key..."
keyctl pkey_sign $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 hash=sha1 > /tmp/sig
echo "Verify with pub key..."
keyctl pkey_verify $PRIV_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

echo "Enc with pub key..."
keyctl pkey_encrypt $PUB_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.pub
echo "Dec with priv key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.pub enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Verify with pub key..."
keyctl pkey_verify $PUB_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

Co-developed-by: lei he <helei.sig11@bytedance.com
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Signed-off-by: lei he <helei.sig11@bytedance.com
---
 backends/cryptodev-builtin.c      | 319 +++++++++++++++++++++++++----
 backends/cryptodev-vhost-user.c   |  34 +++-
 backends/cryptodev.c              |  32 ++-
 hw/virtio/virtio-crypto.c         | 326 ++++++++++++++++++++++++------
 include/hw/virtio/virtio-crypto.h |   5 +-
 include/sysemu/cryptodev.h        |  88 ++++++--
 6 files changed, 660 insertions(+), 144 deletions(-)

diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 0671bf9f3e..bae12c7068 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -26,6 +26,7 @@
 #include "qapi/error.h"
 #include "standard-headers/linux/virtio_crypto.h"
 #include "crypto/cipher.h"
+#include "crypto/akcipher.h"
 #include "qom/object.h"
 
 
@@ -41,11 +42,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
 typedef struct CryptoDevBackendBuiltinSession {
     QCryptoCipher *cipher;
     uint8_t direction; /* encryption or decryption */
-    uint8_t type; /* cipher? hash? aead? */
+    uint8_t type; /* cipher? hash? aead? akcipher? */
+    QCryptoAkcipher *akcipher;
     QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
 } CryptoDevBackendBuiltinSession;
 
-/* Max number of symmetric sessions */
+/* Max number of symmetric/asymmetric sessions */
 #define MAX_NUM_SESSIONS 256
 
 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN    512
@@ -80,15 +82,17 @@ static void cryptodev_builtin_init(
     backend->conf.crypto_services =
                          1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
                          1u << VIRTIO_CRYPTO_SERVICE_HASH |
-                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
+                         1u << VIRTIO_CRYPTO_SERVICE_MAC |
+                         1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
     backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
     backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
+    backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
     /*
      * Set the Maximum length of crypto request.
      * Why this value? Just avoid to overflow when
      * memory allocation for each crypto request.
      */
-    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
+    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
     backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
     backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
 
@@ -148,6 +152,100 @@ err:
    return -1;
 }
 
+static int cryptodev_builtin_get_rsa_hash_algo(
+    int virtio_rsa_hash, Error **errp)
+{
+    switch (virtio_rsa_hash) {
+    case VIRTIO_CRYPTO_RSA_MD2:
+        return QCRYPTO_RSA_HASH_ALG_MD2;
+
+    case VIRTIO_CRYPTO_RSA_MD3:
+        return QCRYPTO_RSA_HASH_ALG_MD3;
+
+    case VIRTIO_CRYPTO_RSA_MD4:
+        return QCRYPTO_RSA_HASH_ALG_MD4;
+
+    case VIRTIO_CRYPTO_RSA_MD5:
+        return QCRYPTO_RSA_HASH_ALG_MD5;
+
+    case VIRTIO_CRYPTO_RSA_SHA1:
+        return QCRYPTO_RSA_HASH_ALG_SHA1;
+
+    case VIRTIO_CRYPTO_RSA_SHA256:
+        return QCRYPTO_RSA_HASH_ALG_SHA256;
+
+    case VIRTIO_CRYPTO_RSA_SHA384:
+        return QCRYPTO_RSA_HASH_ALG_SHA384;
+
+    case VIRTIO_CRYPTO_RSA_SHA512:
+        return QCRYPTO_RSA_HASH_ALG_SHA512;
+
+    case VIRTIO_CRYPTO_RSA_SHA224:
+        return QCRYPTO_RSA_HASH_ALG_SHA224;
+
+    default:
+        error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
+        return -1;
+    }
+}
+
+static int cryptodev_builtin_set_rsa_options(
+                    int virtio_padding_algo,
+                    int virtio_hash_algo,
+                    QCryptoRsaOptions *opt,
+                    Error **errp)
+{
+    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
+        opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1;
+        opt->hash_algo =
+            cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
+        if (opt->hash_algo < 0) {
+            return -1;
+        }
+        return 0;
+    }
+
+    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
+        opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW;
+        return 0;
+    }
+
+    error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
+    return -1;
+}
+
+static int cryptodev_builtin_set_ecdsa_options(int virtio_curve_id,
+                    QCryptoEcdsaOptions *opt, Error **errp)
+{
+    switch (virtio_curve_id) {
+    case VIRTIO_CRYPTO_CURVE_NIST_P192:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P192;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P224:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P224;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P256:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P256;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P384:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P384;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P521:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P521;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported curve id: %d", virtio_curve_id);
+        return -1;
+    }
+
+    return 0;
+}
+
 static int cryptodev_builtin_create_cipher_session(
                     CryptoDevBackendBuiltin *builtin,
                     CryptoDevBackendSymSessionInfo *sess_info,
@@ -240,26 +338,100 @@ static int cryptodev_builtin_create_cipher_session(
     return index;
 }
 
-static int64_t cryptodev_builtin_sym_create_session(
+static int cryptodev_builtin_create_akcipher_session(
+                    CryptoDevBackendBuiltin *builtin,
+                    CryptoDevBackendAsymSessionInfo *sess_info,
+                    Error **errp)
+{
+    CryptoDevBackendBuiltinSession *sess;
+    QCryptoAkcipher *akcipher;
+    int index;
+    QCryptoAkcipherAlgorithm alg;
+    QCryptoAkcipherKeyType type;
+    QCryptoRsaOptions rsa_opt;
+    QCryptoEcdsaOptions ecdsa_opt;
+    void *opt;
+
+    switch (sess_info->algo) {
+    case VIRTIO_CRYPTO_AKCIPHER_RSA:
+        alg = QCRYPTO_AKCIPHER_ALG_RSA;
+        if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
+            sess_info->u.rsa.hash_algo, &rsa_opt, errp) != 0) {
+            return -1;
+        }
+        opt = (void *)&rsa_opt;
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+        alg = QCRYPTO_AKCIPHER_ALG_ECDSA;
+        if (cryptodev_builtin_set_ecdsa_options(sess_info->u.ecdsa.curve_id,
+            &ecdsa_opt, errp) != 0) {
+            return -1;
+        }
+        opt = (void *)&ecdsa_opt;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
+        return -1;
+    }
+
+    switch (sess_info->keytype) {
+    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+        type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+        type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
+        return -1;
+    }
+
+    index = cryptodev_builtin_get_unused_session_index(builtin);
+    if (index < 0) {
+        error_setg(errp, "Total number of sessions created exceeds %u",
+                   MAX_NUM_SESSIONS);
+        return -1;
+    }
+
+    akcipher = qcrypto_akcipher_new(alg, type, sess_info->key,
+                                    sess_info->keylen, opt, errp);
+    if (!akcipher) {
+        return -1;
+    }
+
+    sess = g_new0(CryptoDevBackendBuiltinSession, 1);
+    sess->akcipher = akcipher;
+
+    builtin->sessions[index] = sess;
+
+    return index;
+}
+
+static int64_t cryptodev_builtin_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendBuiltin *builtin =
                       CRYPTODEV_BACKEND_BUILTIN(backend);
-    int64_t session_id = -1;
-    int ret;
+    CryptoDevBackendSymSessionInfo *sym_sess_info;
+    CryptoDevBackendAsymSessionInfo *asym_sess_info;
 
     switch (sess_info->op_code) {
     case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
-        ret = cryptodev_builtin_create_cipher_session(
-                           builtin, sess_info, errp);
-        if (ret < 0) {
-            return ret;
-        } else {
-            session_id = ret;
-        }
-        break;
+        sym_sess_info = &sess_info->u.sym_sess_info;
+        return cryptodev_builtin_create_cipher_session(
+                           builtin, sym_sess_info, errp);
+
+    case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+        asym_sess_info = &sess_info->u.asym_sess_info;
+        return cryptodev_builtin_create_akcipher_session(
+                           builtin, asym_sess_info, errp);
+
     case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
     case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
     default:
@@ -268,10 +440,10 @@ static int64_t cryptodev_builtin_sym_create_session(
         return -1;
     }
 
-    return session_id;
+    return -1;
 }
 
-static int cryptodev_builtin_sym_close_session(
+static int cryptodev_builtin_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -288,30 +460,17 @@ static int cryptodev_builtin_sym_close_session(
 }
 
 static int cryptodev_builtin_sym_operation(
-                 CryptoDevBackend *backend,
-                 CryptoDevBackendSymOpInfo *op_info,
-                 uint32_t queue_index, Error **errp)
+                 CryptoDevBackendBuiltinSession *sess,
+                 CryptoDevBackendSymOpInfo *op_info, Error **errp)
 {
-    CryptoDevBackendBuiltin *builtin =
-                      CRYPTODEV_BACKEND_BUILTIN(backend);
-    CryptoDevBackendBuiltinSession *sess;
     int ret;
 
-    if (op_info->session_id >= MAX_NUM_SESSIONS ||
-              builtin->sessions[op_info->session_id] == NULL) {
-        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
-                   op_info->session_id);
-        return -VIRTIO_CRYPTO_INVSESS;
-    }
-
     if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
         error_setg(errp,
                "Algorithm chain is unsupported for cryptdoev-builtin");
         return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    sess = builtin->sessions[op_info->session_id];
-
     if (op_info->iv_len > 0) {
         ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
                                    op_info->iv_len, errp);
@@ -333,9 +492,95 @@ static int cryptodev_builtin_sym_operation(
             return -VIRTIO_CRYPTO_ERR;
         }
     }
+
+    return VIRTIO_CRYPTO_OK;
+}
+
+static int cryptodev_builtin_asym_operation(
+                 CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
+                 CryptoDevBackendAsymOpInfo *op_info, Error **errp)
+{
+    int ret;
+
+    switch (op_code) {
+    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+        ret = qcrypto_akcipher_encrypt(sess->akcipher,
+                                       op_info->src, op_info->src_len,
+                                       op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+        ret = qcrypto_akcipher_decrypt(sess->akcipher,
+                                       op_info->src, op_info->src_len,
+                                       op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+        ret = qcrypto_akcipher_sign(sess->akcipher,
+                                    op_info->src, op_info->src_len,
+                                    op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+        ret = qcrypto_akcipher_verify(sess->akcipher,
+                                      op_info->src, op_info->src_len,
+                                      op_info->dst, op_info->dst_len, errp);
+    break;
+
+    default:
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    if (ret < 0) {
+        if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+            return -VIRTIO_CRYPTO_KEY_REJECTED;
+        }
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    /* Buffer is too short */
+    if (unlikely(ret > op_info->dst_len)) {
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    op_info->dst_len = ret;
+
     return VIRTIO_CRYPTO_OK;
 }
 
+static int cryptodev_builtin_operation(
+                 CryptoDevBackend *backend,
+                 CryptoDevBackendOpInfo *op_info,
+                 uint32_t queue_index, Error **errp)
+{
+    CryptoDevBackendBuiltin *builtin =
+                      CRYPTODEV_BACKEND_BUILTIN(backend);
+    CryptoDevBackendBuiltinSession *sess;
+    CryptoDevBackendSymOpInfo *sym_op_info;
+    CryptoDevBackendAsymOpInfo *asym_op_info;
+    enum CryptoDevBackendAlgType algtype = op_info->algtype;
+    int ret = -VIRTIO_CRYPTO_ERR;
+
+    if (op_info->session_id >= MAX_NUM_SESSIONS ||
+              builtin->sessions[op_info->session_id] == NULL) {
+        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
+                   op_info->session_id);
+        return -VIRTIO_CRYPTO_INVSESS;
+    }
+
+    sess = builtin->sessions[op_info->session_id];
+    if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
+        sym_op_info = op_info->u.sym_op_info;
+        ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp);
+    } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
+        asym_op_info = op_info->u.asym_op_info;
+        ret = cryptodev_builtin_asym_operation(sess, op_info->op_code,
+                                               asym_op_info, errp);
+    }
+
+    return ret;
+}
+
 static void cryptodev_builtin_cleanup(
              CryptoDevBackend *backend,
              Error **errp)
@@ -348,7 +593,7 @@ static void cryptodev_builtin_cleanup(
 
     for (i = 0; i < MAX_NUM_SESSIONS; i++) {
         if (builtin->sessions[i] != NULL) {
-            cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort);
+            cryptodev_builtin_close_session(backend, i, 0, &error_abort);
         }
     }
 
@@ -370,9 +615,9 @@ cryptodev_builtin_class_init(ObjectClass *oc, void *data)
 
     bc->init = cryptodev_builtin_init;
     bc->cleanup = cryptodev_builtin_cleanup;
-    bc->create_session = cryptodev_builtin_sym_create_session;
-    bc->close_session = cryptodev_builtin_sym_close_session;
-    bc->do_sym_op = cryptodev_builtin_sym_operation;
+    bc->create_session = cryptodev_builtin_create_session;
+    bc->close_session = cryptodev_builtin_close_session;
+    bc->do_op = cryptodev_builtin_operation;
 }
 
 static const TypeInfo cryptodev_builtin_info = {
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index bedb452474..5443a59153 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -259,7 +259,33 @@ static int64_t cryptodev_vhost_user_sym_create_session(
     return -1;
 }
 
-static int cryptodev_vhost_user_sym_close_session(
+static int64_t cryptodev_vhost_user_create_session(
+           CryptoDevBackend *backend,
+           CryptoDevBackendSessionInfo *sess_info,
+           uint32_t queue_index, Error **errp)
+{
+    uint32_t op_code = sess_info->op_code;
+    CryptoDevBackendSymSessionInfo *sym_sess_info;
+
+    switch (op_code) {
+    case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
+    case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
+    case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
+    case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
+        sym_sess_info = &sess_info->u.sym_sess_info;
+        return cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
+                   queue_index, errp);
+    default:
+        error_setg(errp, "Unsupported opcode :%" PRIu32 "",
+                   sess_info->op_code);
+        return -1;
+
+    }
+
+    return -1;
+}
+
+static int cryptodev_vhost_user_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -351,9 +377,9 @@ cryptodev_vhost_user_class_init(ObjectClass *oc, void *data)
 
     bc->init = cryptodev_vhost_user_init;
     bc->cleanup = cryptodev_vhost_user_cleanup;
-    bc->create_session = cryptodev_vhost_user_sym_create_session;
-    bc->close_session = cryptodev_vhost_user_sym_close_session;
-    bc->do_sym_op = NULL;
+    bc->create_session = cryptodev_vhost_user_create_session;
+    bc->close_session = cryptodev_vhost_user_close_session;
+    bc->do_op = NULL;
 
     object_class_property_add_str(oc, "chardev",
                                   cryptodev_vhost_user_get_chardev,
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 2b105e433c..33eb4e1a70 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -72,9 +72,9 @@ void cryptodev_backend_cleanup(
     }
 }
 
-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendClass *bc =
@@ -87,7 +87,7 @@ int64_t cryptodev_backend_sym_create_session(
     return -1;
 }
 
-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -102,16 +102,16 @@ int cryptodev_backend_sym_close_session(
     return -1;
 }
 
-static int cryptodev_backend_sym_operation(
+static int cryptodev_backend_operation(
                  CryptoDevBackend *backend,
-                 CryptoDevBackendSymOpInfo *op_info,
+                 CryptoDevBackendOpInfo *op_info,
                  uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendClass *bc =
                       CRYPTODEV_BACKEND_GET_CLASS(backend);
 
-    if (bc->do_sym_op) {
-        return bc->do_sym_op(backend, op_info, queue_index, errp);
+    if (bc->do_op) {
+        return bc->do_op(backend, op_info, queue_index, errp);
     }
 
     return -VIRTIO_CRYPTO_ERR;
@@ -123,20 +123,18 @@ int cryptodev_backend_crypto_operation(
                  uint32_t queue_index, Error **errp)
 {
     VirtIOCryptoReq *req = opaque;
+    CryptoDevBackendOpInfo *op_info = &req->op_info;
+    enum CryptoDevBackendAlgType algtype = req->flags;
 
-    if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
-        CryptoDevBackendSymOpInfo *op_info;
-        op_info = req->u.sym_op_info;
-
-        return cryptodev_backend_sym_operation(backend,
-                         op_info, queue_index, errp);
-    } else {
+    if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
+        && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
         error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "",
-                   req->flags);
-       return -VIRTIO_CRYPTO_NOTSUPP;
+                   algtype);
+
+        return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    return -VIRTIO_CRYPTO_ERR;
+    return cryptodev_backend_operation(backend, op_info, queue_index, errp);
 }
 
 static void
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index dcd80b904d..fc1ca90202 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -83,7 +83,8 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
                struct iovec *iov, unsigned int out_num)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
-    CryptoDevBackendSymSessionInfo info;
+    CryptoDevBackendSessionInfo info;
+    CryptoDevBackendSymSessionInfo *sym_info;
     int64_t session_id;
     int queue_index;
     uint32_t op_type;
@@ -92,11 +93,13 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
 
     memset(&info, 0, sizeof(info));
     op_type = ldl_le_p(&sess_req->op_type);
-    info.op_type = op_type;
     info.op_code = opcode;
 
+    sym_info = &info.u.sym_sess_info;
+    sym_info->op_type = op_type;
+
     if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
-        ret = virtio_crypto_cipher_session_helper(vdev, &info,
+        ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
                            &sess_req->u.cipher.para,
                            &iov, &out_num);
         if (ret < 0) {
@@ -105,47 +108,47 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
         size_t s;
         /* cipher part */
-        ret = virtio_crypto_cipher_session_helper(vdev, &info,
+        ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
                            &sess_req->u.chain.para.cipher_param,
                            &iov, &out_num);
         if (ret < 0) {
             goto err;
         }
         /* hash part */
-        info.alg_chain_order = ldl_le_p(
+        sym_info->alg_chain_order = ldl_le_p(
                                      &sess_req->u.chain.para.alg_chain_order);
-        info.add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
-        info.hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
-        if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
-            info.hash_alg = ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
-            info.auth_key_len = ldl_le_p(
+        sym_info->add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
+        sym_info->hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
+        if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
+            sym_info->hash_alg =
+                ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
+            sym_info->auth_key_len = ldl_le_p(
                              &sess_req->u.chain.para.u.mac_param.auth_key_len);
-            info.hash_result_len = ldl_le_p(
+            sym_info->hash_result_len = ldl_le_p(
                            &sess_req->u.chain.para.u.mac_param.hash_result_len);
-            if (info.auth_key_len > vcrypto->conf.max_auth_key_len) {
+            if (sym_info->auth_key_len > vcrypto->conf.max_auth_key_len) {
                 error_report("virtio-crypto length of auth key is too big: %u",
-                             info.auth_key_len);
+                             sym_info->auth_key_len);
                 ret = -VIRTIO_CRYPTO_ERR;
                 goto err;
             }
             /* get auth key */
-            if (info.auth_key_len > 0) {
-                DPRINTF("auth_keylen=%" PRIu32 "\n", info.auth_key_len);
-                info.auth_key = g_malloc(info.auth_key_len);
-                s = iov_to_buf(iov, out_num, 0, info.auth_key,
-                               info.auth_key_len);
-                if (unlikely(s != info.auth_key_len)) {
+            if (sym_info->auth_key_len > 0) {
+                sym_info->auth_key = g_malloc(sym_info->auth_key_len);
+                s = iov_to_buf(iov, out_num, 0, sym_info->auth_key,
+                               sym_info->auth_key_len);
+                if (unlikely(s != sym_info->auth_key_len)) {
                     virtio_error(vdev,
                           "virtio-crypto authenticated key incorrect");
                     ret = -EFAULT;
                     goto err;
                 }
-                iov_discard_front(&iov, &out_num, info.auth_key_len);
+                iov_discard_front(&iov, &out_num, sym_info->auth_key_len);
             }
-        } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
-            info.hash_alg = ldl_le_p(
+        } else if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
+            sym_info->hash_alg = ldl_le_p(
                              &sess_req->u.chain.para.u.hash_param.algo);
-            info.hash_result_len = ldl_le_p(
+            sym_info->hash_result_len = ldl_le_p(
                         &sess_req->u.chain.para.u.hash_param.hash_result_len);
         } else {
             /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */
@@ -161,13 +164,10 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     }
 
     queue_index = virtio_crypto_vq2q(queue_id);
-    session_id = cryptodev_backend_sym_create_session(
+    session_id = cryptodev_backend_create_session(
                                      vcrypto->cryptodev,
                                      &info, queue_index, &local_err);
     if (session_id >= 0) {
-        DPRINTF("create session_id=%" PRIu64 " successfully\n",
-                session_id);
-
         ret = session_id;
     } else {
         if (local_err) {
@@ -177,11 +177,82 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     }
 
 err:
-    g_free(info.cipher_key);
-    g_free(info.auth_key);
+    g_free(sym_info->cipher_key);
+    g_free(sym_info->auth_key);
     return ret;
 }
 
+static int64_t
+virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto,
+               struct virtio_crypto_akcipher_create_session_req *sess_req,
+               uint32_t queue_id, uint32_t opcode,
+               struct iovec *iov, unsigned int out_num)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendSessionInfo info = {0};
+    CryptoDevBackendAsymSessionInfo *asym_info;
+    int64_t session_id;
+    int queue_index;
+    uint32_t algo, keytype, keylen;
+    uint8_t *key = NULL;
+    Error *local_err = NULL;
+
+    algo = ldl_le_p(&sess_req->para.algo);
+    keytype = ldl_le_p(&sess_req->para.keytype);
+    keylen = ldl_le_p(&sess_req->para.keylen);
+
+    if ((keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC)
+         && (keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE)) {
+        error_report("unsupported asym keytype: %d", keytype);
+        return -VIRTIO_CRYPTO_NOTSUPP;
+    }
+
+    if (keylen) {
+        key = g_malloc(keylen);
+        if (iov_to_buf(iov, out_num, 0, key, keylen) != keylen) {
+            virtio_error(vdev, "virtio-crypto asym key incorrect");
+            g_free(key);
+            return -EFAULT;
+        }
+        iov_discard_front(&iov, &out_num, keylen);
+    }
+
+    info.op_code = opcode;
+    asym_info = &info.u.asym_sess_info;
+    asym_info->algo = algo;
+    asym_info->keytype = keytype;
+    asym_info->keylen = keylen;
+    asym_info->key = key;
+    switch (asym_info->algo) {
+    case VIRTIO_CRYPTO_AKCIPHER_RSA:
+        asym_info->u.rsa.padding_algo =
+            ldl_le_p(&sess_req->para.u.rsa.padding_algo);
+        asym_info->u.rsa.hash_algo =
+            ldl_le_p(&sess_req->para.u.rsa.hash_algo);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+        asym_info->u.ecdsa.curve_id =
+            ldl_le_p(&sess_req->para.u.ecdsa.curve_id);
+        break;
+
+    default:
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    queue_index = virtio_crypto_vq2q(queue_id);
+    session_id = cryptodev_backend_create_session(vcrypto->cryptodev, &info,
+                     queue_index, &local_err);
+    if (session_id < 0) {
+        if (local_err) {
+            error_report_err(local_err);
+        }
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    return session_id;
+}
+
 static uint8_t
 virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
          struct virtio_crypto_destroy_session_req *close_sess_req,
@@ -193,9 +264,8 @@ virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
     Error *local_err = NULL;
 
     session_id = ldq_le_p(&close_sess_req->session_id);
-    DPRINTF("close session, id=%" PRIu64 "\n", session_id);
 
-    ret = cryptodev_backend_sym_close_session(
+    ret = cryptodev_backend_close_session(
               vcrypto->cryptodev, session_id, queue_id, &local_err);
     if (ret == 0) {
         status = VIRTIO_CRYPTO_OK;
@@ -260,13 +330,22 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         opcode = ldl_le_p(&ctrl.header.opcode);
         queue_id = ldl_le_p(&ctrl.header.queue_id);
 
+        memset(&input, 0, sizeof(input));
         switch (opcode) {
         case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
-            memset(&input, 0, sizeof(input));
             session_id = virtio_crypto_create_sym_session(vcrypto,
                              &ctrl.u.sym_create_session,
                              queue_id, opcode,
                              out_iov, out_num);
+            goto check_session;
+
+        case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+            session_id = virtio_crypto_create_asym_session(vcrypto,
+                             &ctrl.u.akcipher_create_session,
+                             queue_id, opcode,
+                             out_iov, out_num);
+
+check_session:
             /* Serious errors, need to reset virtio crypto device */
             if (session_id == -EFAULT) {
                 virtqueue_detach_element(vq, elem, 0);
@@ -290,10 +369,12 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
             virtqueue_push(vq, elem, sizeof(input));
             virtio_notify(vdev, vq);
             break;
+
         case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION:
         case VIRTIO_CRYPTO_HASH_DESTROY_SESSION:
         case VIRTIO_CRYPTO_MAC_DESTROY_SESSION:
         case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION:
+        case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION:
             status = virtio_crypto_handle_close_session(vcrypto,
                    &ctrl.u.destroy_session, queue_id);
             /* The status only occupy one byte, we can directly use it */
@@ -311,7 +392,6 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
         default:
             error_report("virtio-crypto unsupported ctrl opcode: %d", opcode);
-            memset(&input, 0, sizeof(input));
             stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP);
             s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input));
             if (unlikely(s != sizeof(input))) {
@@ -339,28 +419,37 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq,
     req->in_num = 0;
     req->in_len = 0;
     req->flags = CRYPTODEV_BACKEND_ALG__MAX;
-    req->u.sym_op_info = NULL;
+    memset(&req->op_info, 0x00, sizeof(req->op_info));
 }
 
 static void virtio_crypto_free_request(VirtIOCryptoReq *req)
 {
-    if (req) {
-        if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
-            size_t max_len;
-            CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info;
-
-            max_len = op_info->iv_len +
-                      op_info->aad_len +
-                      op_info->src_len +
-                      op_info->dst_len +
-                      op_info->digest_result_len;
-
-            /* Zeroize and free request data structure */
-            memset(op_info, 0, sizeof(*op_info) + max_len);
+    if (!req) {
+        return;
+    }
+
+    if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
+        size_t max_len;
+        CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
+
+        max_len = op_info->iv_len +
+                  op_info->aad_len +
+                  op_info->src_len +
+                  op_info->dst_len +
+                  op_info->digest_result_len;
+
+        /* Zeroize and free request data structure */
+        memset(op_info, 0, sizeof(*op_info) + max_len);
+        g_free(op_info);
+    } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+        CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
+        if (op_info) {
+            memset(op_info, 0, sizeof(*op_info));
             g_free(op_info);
         }
-        g_free(req);
     }
+
+    g_free(req);
 }
 
 static void
@@ -397,6 +486,35 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev,
     }
 }
 
+static void
+virtio_crypto_akcipher_input_data_helper(VirtIODevice *vdev,
+        VirtIOCryptoReq *req, int32_t status,
+        CryptoDevBackendAsymOpInfo *asym_op_info)
+{
+    size_t s, len;
+
+    if (status != VIRTIO_CRYPTO_OK) {
+        return;
+    }
+
+    len = asym_op_info->dst_len;
+    if (!len) {
+        return;
+    }
+
+    s = iov_from_buf(req->in_iov, req->in_num, 0, asym_op_info->dst, len);
+    if (s != len) {
+        virtio_error(vdev, "virtio-crypto asym dest data incorrect");
+        return;
+    }
+
+    iov_discard_front(&req->in_iov, &req->in_num, len);
+
+    /* For akcipher, dst_len may be changed after operation */
+    req->in_len = sizeof(struct virtio_crypto_inhdr) + asym_op_info->dst_len;
+}
+
+
 static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)
 {
     VirtIOCrypto *vcrypto = req->vcrypto;
@@ -404,7 +522,10 @@ static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)
 
     if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
         virtio_crypto_sym_input_data_helper(vdev, req, status,
-                                            req->u.sym_op_info);
+                                            req->op_info.u.sym_op_info);
+    } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+        virtio_crypto_akcipher_input_data_helper(vdev, req, status,
+                                             req->op_info.u.asym_op_info);
     }
     stb_p(&req->in->status, status);
     virtqueue_push(req->vq, &req->elem, req->in_len);
@@ -543,41 +664,100 @@ err:
 static int
 virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto,
                struct virtio_crypto_sym_data_req *req,
-               CryptoDevBackendSymOpInfo **sym_op_info,
+               CryptoDevBackendOpInfo *op_info,
                struct iovec *iov, unsigned int out_num)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendSymOpInfo *sym_op_info;
     uint32_t op_type;
-    CryptoDevBackendSymOpInfo *op_info;
 
     op_type = ldl_le_p(&req->op_type);
-
     if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
-        op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
+        sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
                                               NULL, iov, out_num);
-        if (!op_info) {
+        if (!sym_op_info) {
             return -EFAULT;
         }
-        op_info->op_type = op_type;
     } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
-        op_info = virtio_crypto_sym_op_helper(vdev, NULL,
+        sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL,
                                               &req->u.chain.para,
                                               iov, out_num);
-        if (!op_info) {
+        if (!sym_op_info) {
             return -EFAULT;
         }
-        op_info->op_type = op_type;
     } else {
         /* VIRTIO_CRYPTO_SYM_OP_NONE */
         error_report("virtio-crypto unsupported cipher type");
         return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    *sym_op_info = op_info;
+    sym_op_info->op_type = op_type;
+    op_info->u.sym_op_info = sym_op_info;
 
     return 0;
 }
 
+static int
+virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto,
+               struct virtio_crypto_akcipher_data_req *req,
+               CryptoDevBackendOpInfo *op_info,
+               struct iovec *iov, unsigned int out_num)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendAsymOpInfo *asym_op_info;
+    uint32_t src_len;
+    uint32_t dst_len;
+    uint32_t len;
+    uint8_t *src = NULL;
+    uint8_t *dst = NULL;
+
+    asym_op_info = g_malloc0(sizeof(CryptoDevBackendAsymOpInfo));
+    src_len = ldl_le_p(&req->para.src_data_len);
+    dst_len = ldl_le_p(&req->para.dst_data_len);
+
+    if (src_len > 0) {
+        src = g_malloc0(src_len);
+        len = iov_to_buf(iov, out_num, 0, src, src_len);
+        if (unlikely(len != src_len)) {
+            virtio_error(vdev, "virtio-crypto asym src data incorrect"
+                         "expected %u, actual %u", src_len, len);
+            goto err;
+        }
+
+        iov_discard_front(&iov, &out_num, src_len);
+    }
+
+    if (dst_len > 0) {
+        dst = g_malloc0(dst_len);
+
+        if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+            len = iov_to_buf(iov, out_num, 0, dst, dst_len);
+            if (unlikely(len != dst_len)) {
+                virtio_error(vdev, "virtio-crypto asym dst data incorrect"
+                             "expected %u, actual %u", dst_len, len);
+                goto err;
+            }
+
+            iov_discard_front(&iov, &out_num, dst_len);
+        }
+    }
+
+    asym_op_info->src_len = src_len;
+    asym_op_info->dst_len = dst_len;
+    asym_op_info->src = src;
+    asym_op_info->dst = dst;
+    op_info->u.asym_op_info = asym_op_info;
+
+    return 0;
+
+ err:
+    g_free(asym_op_info);
+    g_free(src);
+    g_free(dst);
+
+    return -EFAULT;
+}
+
 static int
 virtio_crypto_handle_request(VirtIOCryptoReq *request)
 {
@@ -595,8 +775,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
     unsigned out_num;
     uint32_t opcode;
     uint8_t status = VIRTIO_CRYPTO_ERR;
-    uint64_t session_id;
-    CryptoDevBackendSymOpInfo *sym_op_info = NULL;
+    CryptoDevBackendOpInfo *op_info = &request->op_info;
     Error *local_err = NULL;
 
     if (elem->out_num < 1 || elem->in_num < 1) {
@@ -639,15 +818,28 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
     request->in_iov = in_iov;
 
     opcode = ldl_le_p(&req.header.opcode);
-    session_id = ldq_le_p(&req.header.session_id);
+    op_info->session_id = ldq_le_p(&req.header.session_id);
+    op_info->op_code = opcode;
 
     switch (opcode) {
     case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
     case VIRTIO_CRYPTO_CIPHER_DECRYPT:
+        op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_SYM;
         ret = virtio_crypto_handle_sym_req(vcrypto,
-                         &req.u.sym_req,
-                         &sym_op_info,
+                         &req.u.sym_req, op_info,
+                         out_iov, out_num);
+        goto check_result;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+        op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_ASYM;
+        ret = virtio_crypto_handle_asym_req(vcrypto,
+                         &req.u.akcipher_req, op_info,
                          out_iov, out_num);
+
+check_result:
         /* Serious errors, need to reset virtio crypto device */
         if (ret == -EFAULT) {
             return -1;
@@ -655,11 +847,8 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
             virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP);
             virtio_crypto_free_request(request);
         } else {
-            sym_op_info->session_id = session_id;
 
             /* Set request's parameter */
-            request->flags = CRYPTODEV_BACKEND_ALG_SYM;
-            request->u.sym_op_info = sym_op_info;
             ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev,
                                     request, queue_index, &local_err);
             if (ret < 0) {
@@ -674,6 +863,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
             virtio_crypto_free_request(request);
         }
         break;
+
     case VIRTIO_CRYPTO_HASH:
     case VIRTIO_CRYPTO_MAC:
     case VIRTIO_CRYPTO_AEAD_ENCRYPT:
@@ -779,6 +969,7 @@ static void virtio_crypto_init_config(VirtIODevice *vdev)
     vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l;
     vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h;
     vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo;
+    vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo;
     vcrypto->conf.max_cipher_key_len =
                   vcrypto->conf.cryptodev->conf.max_cipher_key_len;
     vcrypto->conf.max_auth_key_len =
@@ -891,6 +1082,7 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config)
     stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len);
     stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len);
     stq_le_p(&crypto_cfg.max_size, c->conf.max_size);
+    stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo);
 
     memcpy(config, &crypto_cfg, c->config_size);
 }
diff --git a/include/hw/virtio/virtio-crypto.h b/include/hw/virtio/virtio-crypto.h
index a2228d7b2e..348749f5d5 100644
--- a/include/hw/virtio/virtio-crypto.h
+++ b/include/hw/virtio/virtio-crypto.h
@@ -50,6 +50,7 @@ typedef struct VirtIOCryptoConf {
     uint32_t mac_algo_l;
     uint32_t mac_algo_h;
     uint32_t aead_algo;
+    uint32_t akcipher_algo;
 
     /* Maximum length of cipher key */
     uint32_t max_cipher_key_len;
@@ -71,9 +72,7 @@ typedef struct VirtIOCryptoReq {
     size_t in_len;
     VirtQueue *vq;
     struct VirtIOCrypto *vcrypto;
-    union {
-        CryptoDevBackendSymOpInfo *sym_op_info;
-    } u;
+    CryptoDevBackendOpInfo op_info;
 } VirtIOCryptoReq;
 
 typedef struct VirtIOCryptoQueue {
diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h
index f4d4057d4d..b306775849 100644
--- a/include/sysemu/cryptodev.h
+++ b/include/sysemu/cryptodev.h
@@ -50,13 +50,13 @@ typedef struct CryptoDevBackendClient
 
 enum CryptoDevBackendAlgType {
     CRYPTODEV_BACKEND_ALG_SYM,
+    CRYPTODEV_BACKEND_ALG_ASYM,
     CRYPTODEV_BACKEND_ALG__MAX,
 };
 
 /**
  * CryptoDevBackendSymSessionInfo:
  *
- * @op_code: operation code (refer to virtio_crypto.h)
  * @cipher_alg: algorithm type of CIPHER
  * @key_len: byte length of cipher key
  * @hash_alg: algorithm type of HASH/MAC
@@ -74,7 +74,6 @@ enum CryptoDevBackendAlgType {
  */
 typedef struct CryptoDevBackendSymSessionInfo {
     /* corresponding with virtio crypto spec */
-    uint32_t op_code;
     uint32_t cipher_alg;
     uint32_t key_len;
     uint32_t hash_alg;
@@ -89,11 +88,41 @@ typedef struct CryptoDevBackendSymSessionInfo {
     uint8_t *auth_key;
 } CryptoDevBackendSymSessionInfo;
 
+/**
+ * CryptoDevBackendAsymSessionInfo:
+ */
+typedef struct CryptoDevBackendRsaPara {
+    uint32_t padding_algo;
+    uint32_t hash_algo;
+} CryptoDevBackendRsaPara;
+
+typedef struct CryptoDevBackendEcdsaPara {
+    uint32_t curve_id;
+} CryptoDevBackendEcdsaPara;
+
+typedef struct CryptoDevBackendAsymSessionInfo {
+    /* corresponding with virtio crypto spec */
+    uint32_t algo;
+    uint32_t keytype;
+    uint32_t keylen;
+    uint8_t *key;
+    union {
+        CryptoDevBackendRsaPara rsa;
+        CryptoDevBackendEcdsaPara ecdsa;
+    } u;
+} CryptoDevBackendAsymSessionInfo;
+
+typedef struct CryptoDevBackendSessionInfo {
+    uint32_t op_code;
+    union {
+        CryptoDevBackendSymSessionInfo sym_sess_info;
+        CryptoDevBackendAsymSessionInfo asym_sess_info;
+    } u;
+} CryptoDevBackendSessionInfo;
+
 /**
  * CryptoDevBackendSymOpInfo:
  *
- * @session_id: session index which was previously
- *              created by cryptodev_backend_sym_create_session()
  * @aad_len: byte length of additional authenticated data
  * @iv_len: byte length of initialization vector or counter
  * @src_len: byte length of source data
@@ -119,7 +148,6 @@ typedef struct CryptoDevBackendSymSessionInfo {
  *
  */
 typedef struct CryptoDevBackendSymOpInfo {
-    uint64_t session_id;
     uint32_t aad_len;
     uint32_t iv_len;
     uint32_t src_len;
@@ -138,6 +166,33 @@ typedef struct CryptoDevBackendSymOpInfo {
     uint8_t data[];
 } CryptoDevBackendSymOpInfo;
 
+
+/**
+ * CryptoDevBackendAsymOpInfo:
+ *
+ * @src_len: byte length of source data
+ * @dst_len: byte length of destination data
+ * @src: point to the source data
+ * @dst: point to the destination data
+ *
+ */
+typedef struct CryptoDevBackendAsymOpInfo {
+    uint32_t src_len;
+    uint32_t dst_len;
+    uint8_t *src;
+    uint8_t *dst;
+} CryptoDevBackendAsymOpInfo;
+
+typedef struct CryptoDevBackendOpInfo {
+    enum CryptoDevBackendAlgType algtype;
+    uint32_t op_code;
+    uint64_t session_id;
+    union {
+        CryptoDevBackendSymOpInfo *sym_op_info;
+        CryptoDevBackendAsymOpInfo *asym_op_info;
+    } u;
+} CryptoDevBackendOpInfo;
+
 struct CryptoDevBackendClass {
     ObjectClass parent_class;
 
@@ -145,13 +200,13 @@ struct CryptoDevBackendClass {
     void (*cleanup)(CryptoDevBackend *backend, Error **errp);
 
     int64_t (*create_session)(CryptoDevBackend *backend,
-                       CryptoDevBackendSymSessionInfo *sess_info,
+                       CryptoDevBackendSessionInfo *sess_info,
                        uint32_t queue_index, Error **errp);
     int (*close_session)(CryptoDevBackend *backend,
                            uint64_t session_id,
                            uint32_t queue_index, Error **errp);
-    int (*do_sym_op)(CryptoDevBackend *backend,
-                     CryptoDevBackendSymOpInfo *op_info,
+    int (*do_op)(CryptoDevBackend *backend,
+                     CryptoDevBackendOpInfo *op_info,
                      uint32_t queue_index, Error **errp);
 };
 
@@ -190,6 +245,7 @@ struct CryptoDevBackendConf {
     uint32_t mac_algo_l;
     uint32_t mac_algo_h;
     uint32_t aead_algo;
+    uint32_t akcipher_algo;
     /* Maximum length of cipher key */
     uint32_t max_cipher_key_len;
     /* Maximum length of authenticated key */
@@ -247,34 +303,34 @@ void cryptodev_backend_cleanup(
            Error **errp);
 
 /**
- * cryptodev_backend_sym_create_session:
+ * cryptodev_backend_create_session:
  * @backend: the cryptodev backend object
  * @sess_info: parameters needed by session creating
  * @queue_index: queue index of cryptodev backend client
  * @errp: pointer to a NULL-initialized error object
  *
- * Create a session for symmetric algorithms
+ * Create a session for symmetric/symmetric algorithms
  *
  * Returns: session id on success, or -1 on error
  */
-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp);
 
 /**
- * cryptodev_backend_sym_close_session:
+ * cryptodev_backend_close_session:
  * @backend: the cryptodev backend object
  * @session_id: the session id
  * @queue_index: queue index of cryptodev backend client
  * @errp: pointer to a NULL-initialized error object
  *
- * Close a session for symmetric algorithms which was previously
- * created by cryptodev_backend_sym_create_session()
+ * Close a session for which was previously
+ * created by cryptodev_backend_create_session()
  *
  * Returns: 0 on success, or Negative on error
  */
-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp);
-- 
2.25.1


_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 6/6] virtio-crypto: Introduce RSA algorithm
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: jasowang, virtualization, qemu-devel, linux-crypto, herbert, zhenwei pi

There are two parts in this patch:
1, support akcipher service by cryptodev-builtin driver
2, virtio-crypto driver supports akcipher service

Then virtio-crypto gets request from guest side, and forwards the
request to builtin driver to handle it.

Test with a guest linux:
1, The self-test framework of crypto layer works fine in guest kernel
2, Test with Linux guest(with asym support), the following script
test(note that pkey_XXX is supported only in a newer version of keyutils):
  - both public key & private key
  - create/close session
  - encrypt/decrypt/sign/verify basic driver operation
  - also test with kernel crypto layer(pkey add/query)

All the cases work fine.

Run script in guest:
rm -rf *.der *.pem *.pfx
modprobe pkcs8_key_parser # if CONFIG_PKCS8_PRIVATE_KEY_PARSER=m
rm -rf /tmp/data
dd if=/dev/random of=/tmp/data count=1 bs=226

openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -subj "/C=CN/ST=BJ/L=HD/O=qemu/OU=dev/CN=qemu/emailAddress=qemu@qemu.org"
openssl pkcs8 -in key.pem -topk8 -nocrypt -outform DER -out key.der
openssl x509 -in cert.pem -inform PEM -outform DER -out cert.der

PRIV_KEY_ID=`cat key.der | keyctl padd asymmetric test_priv_key @s`
echo "priv key id = "$PRIV_KEY_ID
PUB_KEY_ID=`cat cert.der | keyctl padd asymmetric test_pub_key @s`
echo "pub key id = "$PUB_KEY_ID

keyctl pkey_query $PRIV_KEY_ID 0
keyctl pkey_query $PUB_KEY_ID 0

echo "Enc with priv key..."
keyctl pkey_encrypt $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.priv
echo "Dec with pub key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.priv enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Sign with priv key..."
keyctl pkey_sign $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 hash=sha1 > /tmp/sig
echo "Verify with pub key..."
keyctl pkey_verify $PRIV_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

echo "Enc with pub key..."
keyctl pkey_encrypt $PUB_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.pub
echo "Dec with priv key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.pub enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Verify with pub key..."
keyctl pkey_verify $PUB_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

Co-developed-by: lei he <helei.sig11@bytedance.com
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Signed-off-by: lei he <helei.sig11@bytedance.com
---
 backends/cryptodev-builtin.c      | 319 +++++++++++++++++++++++++----
 backends/cryptodev-vhost-user.c   |  34 +++-
 backends/cryptodev.c              |  32 ++-
 hw/virtio/virtio-crypto.c         | 326 ++++++++++++++++++++++++------
 include/hw/virtio/virtio-crypto.h |   5 +-
 include/sysemu/cryptodev.h        |  88 ++++++--
 6 files changed, 660 insertions(+), 144 deletions(-)

diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 0671bf9f3e..bae12c7068 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -26,6 +26,7 @@
 #include "qapi/error.h"
 #include "standard-headers/linux/virtio_crypto.h"
 #include "crypto/cipher.h"
+#include "crypto/akcipher.h"
 #include "qom/object.h"
 
 
@@ -41,11 +42,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
 typedef struct CryptoDevBackendBuiltinSession {
     QCryptoCipher *cipher;
     uint8_t direction; /* encryption or decryption */
-    uint8_t type; /* cipher? hash? aead? */
+    uint8_t type; /* cipher? hash? aead? akcipher? */
+    QCryptoAkcipher *akcipher;
     QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
 } CryptoDevBackendBuiltinSession;
 
-/* Max number of symmetric sessions */
+/* Max number of symmetric/asymmetric sessions */
 #define MAX_NUM_SESSIONS 256
 
 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN    512
@@ -80,15 +82,17 @@ static void cryptodev_builtin_init(
     backend->conf.crypto_services =
                          1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
                          1u << VIRTIO_CRYPTO_SERVICE_HASH |
-                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
+                         1u << VIRTIO_CRYPTO_SERVICE_MAC |
+                         1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
     backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
     backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
+    backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
     /*
      * Set the Maximum length of crypto request.
      * Why this value? Just avoid to overflow when
      * memory allocation for each crypto request.
      */
-    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
+    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
     backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
     backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
 
@@ -148,6 +152,100 @@ err:
    return -1;
 }
 
+static int cryptodev_builtin_get_rsa_hash_algo(
+    int virtio_rsa_hash, Error **errp)
+{
+    switch (virtio_rsa_hash) {
+    case VIRTIO_CRYPTO_RSA_MD2:
+        return QCRYPTO_RSA_HASH_ALG_MD2;
+
+    case VIRTIO_CRYPTO_RSA_MD3:
+        return QCRYPTO_RSA_HASH_ALG_MD3;
+
+    case VIRTIO_CRYPTO_RSA_MD4:
+        return QCRYPTO_RSA_HASH_ALG_MD4;
+
+    case VIRTIO_CRYPTO_RSA_MD5:
+        return QCRYPTO_RSA_HASH_ALG_MD5;
+
+    case VIRTIO_CRYPTO_RSA_SHA1:
+        return QCRYPTO_RSA_HASH_ALG_SHA1;
+
+    case VIRTIO_CRYPTO_RSA_SHA256:
+        return QCRYPTO_RSA_HASH_ALG_SHA256;
+
+    case VIRTIO_CRYPTO_RSA_SHA384:
+        return QCRYPTO_RSA_HASH_ALG_SHA384;
+
+    case VIRTIO_CRYPTO_RSA_SHA512:
+        return QCRYPTO_RSA_HASH_ALG_SHA512;
+
+    case VIRTIO_CRYPTO_RSA_SHA224:
+        return QCRYPTO_RSA_HASH_ALG_SHA224;
+
+    default:
+        error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
+        return -1;
+    }
+}
+
+static int cryptodev_builtin_set_rsa_options(
+                    int virtio_padding_algo,
+                    int virtio_hash_algo,
+                    QCryptoRsaOptions *opt,
+                    Error **errp)
+{
+    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
+        opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1;
+        opt->hash_algo =
+            cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
+        if (opt->hash_algo < 0) {
+            return -1;
+        }
+        return 0;
+    }
+
+    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
+        opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW;
+        return 0;
+    }
+
+    error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
+    return -1;
+}
+
+static int cryptodev_builtin_set_ecdsa_options(int virtio_curve_id,
+                    QCryptoEcdsaOptions *opt, Error **errp)
+{
+    switch (virtio_curve_id) {
+    case VIRTIO_CRYPTO_CURVE_NIST_P192:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P192;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P224:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P224;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P256:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P256;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P384:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P384;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P521:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P521;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported curve id: %d", virtio_curve_id);
+        return -1;
+    }
+
+    return 0;
+}
+
 static int cryptodev_builtin_create_cipher_session(
                     CryptoDevBackendBuiltin *builtin,
                     CryptoDevBackendSymSessionInfo *sess_info,
@@ -240,26 +338,100 @@ static int cryptodev_builtin_create_cipher_session(
     return index;
 }
 
-static int64_t cryptodev_builtin_sym_create_session(
+static int cryptodev_builtin_create_akcipher_session(
+                    CryptoDevBackendBuiltin *builtin,
+                    CryptoDevBackendAsymSessionInfo *sess_info,
+                    Error **errp)
+{
+    CryptoDevBackendBuiltinSession *sess;
+    QCryptoAkcipher *akcipher;
+    int index;
+    QCryptoAkcipherAlgorithm alg;
+    QCryptoAkcipherKeyType type;
+    QCryptoRsaOptions rsa_opt;
+    QCryptoEcdsaOptions ecdsa_opt;
+    void *opt;
+
+    switch (sess_info->algo) {
+    case VIRTIO_CRYPTO_AKCIPHER_RSA:
+        alg = QCRYPTO_AKCIPHER_ALG_RSA;
+        if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
+            sess_info->u.rsa.hash_algo, &rsa_opt, errp) != 0) {
+            return -1;
+        }
+        opt = (void *)&rsa_opt;
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+        alg = QCRYPTO_AKCIPHER_ALG_ECDSA;
+        if (cryptodev_builtin_set_ecdsa_options(sess_info->u.ecdsa.curve_id,
+            &ecdsa_opt, errp) != 0) {
+            return -1;
+        }
+        opt = (void *)&ecdsa_opt;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
+        return -1;
+    }
+
+    switch (sess_info->keytype) {
+    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+        type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+        type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
+        return -1;
+    }
+
+    index = cryptodev_builtin_get_unused_session_index(builtin);
+    if (index < 0) {
+        error_setg(errp, "Total number of sessions created exceeds %u",
+                   MAX_NUM_SESSIONS);
+        return -1;
+    }
+
+    akcipher = qcrypto_akcipher_new(alg, type, sess_info->key,
+                                    sess_info->keylen, opt, errp);
+    if (!akcipher) {
+        return -1;
+    }
+
+    sess = g_new0(CryptoDevBackendBuiltinSession, 1);
+    sess->akcipher = akcipher;
+
+    builtin->sessions[index] = sess;
+
+    return index;
+}
+
+static int64_t cryptodev_builtin_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendBuiltin *builtin =
                       CRYPTODEV_BACKEND_BUILTIN(backend);
-    int64_t session_id = -1;
-    int ret;
+    CryptoDevBackendSymSessionInfo *sym_sess_info;
+    CryptoDevBackendAsymSessionInfo *asym_sess_info;
 
     switch (sess_info->op_code) {
     case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
-        ret = cryptodev_builtin_create_cipher_session(
-                           builtin, sess_info, errp);
-        if (ret < 0) {
-            return ret;
-        } else {
-            session_id = ret;
-        }
-        break;
+        sym_sess_info = &sess_info->u.sym_sess_info;
+        return cryptodev_builtin_create_cipher_session(
+                           builtin, sym_sess_info, errp);
+
+    case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+        asym_sess_info = &sess_info->u.asym_sess_info;
+        return cryptodev_builtin_create_akcipher_session(
+                           builtin, asym_sess_info, errp);
+
     case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
     case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
     default:
@@ -268,10 +440,10 @@ static int64_t cryptodev_builtin_sym_create_session(
         return -1;
     }
 
-    return session_id;
+    return -1;
 }
 
-static int cryptodev_builtin_sym_close_session(
+static int cryptodev_builtin_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -288,30 +460,17 @@ static int cryptodev_builtin_sym_close_session(
 }
 
 static int cryptodev_builtin_sym_operation(
-                 CryptoDevBackend *backend,
-                 CryptoDevBackendSymOpInfo *op_info,
-                 uint32_t queue_index, Error **errp)
+                 CryptoDevBackendBuiltinSession *sess,
+                 CryptoDevBackendSymOpInfo *op_info, Error **errp)
 {
-    CryptoDevBackendBuiltin *builtin =
-                      CRYPTODEV_BACKEND_BUILTIN(backend);
-    CryptoDevBackendBuiltinSession *sess;
     int ret;
 
-    if (op_info->session_id >= MAX_NUM_SESSIONS ||
-              builtin->sessions[op_info->session_id] == NULL) {
-        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
-                   op_info->session_id);
-        return -VIRTIO_CRYPTO_INVSESS;
-    }
-
     if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
         error_setg(errp,
                "Algorithm chain is unsupported for cryptdoev-builtin");
         return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    sess = builtin->sessions[op_info->session_id];
-
     if (op_info->iv_len > 0) {
         ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
                                    op_info->iv_len, errp);
@@ -333,9 +492,95 @@ static int cryptodev_builtin_sym_operation(
             return -VIRTIO_CRYPTO_ERR;
         }
     }
+
+    return VIRTIO_CRYPTO_OK;
+}
+
+static int cryptodev_builtin_asym_operation(
+                 CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
+                 CryptoDevBackendAsymOpInfo *op_info, Error **errp)
+{
+    int ret;
+
+    switch (op_code) {
+    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+        ret = qcrypto_akcipher_encrypt(sess->akcipher,
+                                       op_info->src, op_info->src_len,
+                                       op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+        ret = qcrypto_akcipher_decrypt(sess->akcipher,
+                                       op_info->src, op_info->src_len,
+                                       op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+        ret = qcrypto_akcipher_sign(sess->akcipher,
+                                    op_info->src, op_info->src_len,
+                                    op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+        ret = qcrypto_akcipher_verify(sess->akcipher,
+                                      op_info->src, op_info->src_len,
+                                      op_info->dst, op_info->dst_len, errp);
+    break;
+
+    default:
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    if (ret < 0) {
+        if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+            return -VIRTIO_CRYPTO_KEY_REJECTED;
+        }
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    /* Buffer is too short */
+    if (unlikely(ret > op_info->dst_len)) {
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    op_info->dst_len = ret;
+
     return VIRTIO_CRYPTO_OK;
 }
 
+static int cryptodev_builtin_operation(
+                 CryptoDevBackend *backend,
+                 CryptoDevBackendOpInfo *op_info,
+                 uint32_t queue_index, Error **errp)
+{
+    CryptoDevBackendBuiltin *builtin =
+                      CRYPTODEV_BACKEND_BUILTIN(backend);
+    CryptoDevBackendBuiltinSession *sess;
+    CryptoDevBackendSymOpInfo *sym_op_info;
+    CryptoDevBackendAsymOpInfo *asym_op_info;
+    enum CryptoDevBackendAlgType algtype = op_info->algtype;
+    int ret = -VIRTIO_CRYPTO_ERR;
+
+    if (op_info->session_id >= MAX_NUM_SESSIONS ||
+              builtin->sessions[op_info->session_id] == NULL) {
+        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
+                   op_info->session_id);
+        return -VIRTIO_CRYPTO_INVSESS;
+    }
+
+    sess = builtin->sessions[op_info->session_id];
+    if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
+        sym_op_info = op_info->u.sym_op_info;
+        ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp);
+    } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
+        asym_op_info = op_info->u.asym_op_info;
+        ret = cryptodev_builtin_asym_operation(sess, op_info->op_code,
+                                               asym_op_info, errp);
+    }
+
+    return ret;
+}
+
 static void cryptodev_builtin_cleanup(
              CryptoDevBackend *backend,
              Error **errp)
@@ -348,7 +593,7 @@ static void cryptodev_builtin_cleanup(
 
     for (i = 0; i < MAX_NUM_SESSIONS; i++) {
         if (builtin->sessions[i] != NULL) {
-            cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort);
+            cryptodev_builtin_close_session(backend, i, 0, &error_abort);
         }
     }
 
@@ -370,9 +615,9 @@ cryptodev_builtin_class_init(ObjectClass *oc, void *data)
 
     bc->init = cryptodev_builtin_init;
     bc->cleanup = cryptodev_builtin_cleanup;
-    bc->create_session = cryptodev_builtin_sym_create_session;
-    bc->close_session = cryptodev_builtin_sym_close_session;
-    bc->do_sym_op = cryptodev_builtin_sym_operation;
+    bc->create_session = cryptodev_builtin_create_session;
+    bc->close_session = cryptodev_builtin_close_session;
+    bc->do_op = cryptodev_builtin_operation;
 }
 
 static const TypeInfo cryptodev_builtin_info = {
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index bedb452474..5443a59153 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -259,7 +259,33 @@ static int64_t cryptodev_vhost_user_sym_create_session(
     return -1;
 }
 
-static int cryptodev_vhost_user_sym_close_session(
+static int64_t cryptodev_vhost_user_create_session(
+           CryptoDevBackend *backend,
+           CryptoDevBackendSessionInfo *sess_info,
+           uint32_t queue_index, Error **errp)
+{
+    uint32_t op_code = sess_info->op_code;
+    CryptoDevBackendSymSessionInfo *sym_sess_info;
+
+    switch (op_code) {
+    case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
+    case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
+    case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
+    case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
+        sym_sess_info = &sess_info->u.sym_sess_info;
+        return cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
+                   queue_index, errp);
+    default:
+        error_setg(errp, "Unsupported opcode :%" PRIu32 "",
+                   sess_info->op_code);
+        return -1;
+
+    }
+
+    return -1;
+}
+
+static int cryptodev_vhost_user_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -351,9 +377,9 @@ cryptodev_vhost_user_class_init(ObjectClass *oc, void *data)
 
     bc->init = cryptodev_vhost_user_init;
     bc->cleanup = cryptodev_vhost_user_cleanup;
-    bc->create_session = cryptodev_vhost_user_sym_create_session;
-    bc->close_session = cryptodev_vhost_user_sym_close_session;
-    bc->do_sym_op = NULL;
+    bc->create_session = cryptodev_vhost_user_create_session;
+    bc->close_session = cryptodev_vhost_user_close_session;
+    bc->do_op = NULL;
 
     object_class_property_add_str(oc, "chardev",
                                   cryptodev_vhost_user_get_chardev,
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 2b105e433c..33eb4e1a70 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -72,9 +72,9 @@ void cryptodev_backend_cleanup(
     }
 }
 
-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendClass *bc =
@@ -87,7 +87,7 @@ int64_t cryptodev_backend_sym_create_session(
     return -1;
 }
 
-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -102,16 +102,16 @@ int cryptodev_backend_sym_close_session(
     return -1;
 }
 
-static int cryptodev_backend_sym_operation(
+static int cryptodev_backend_operation(
                  CryptoDevBackend *backend,
-                 CryptoDevBackendSymOpInfo *op_info,
+                 CryptoDevBackendOpInfo *op_info,
                  uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendClass *bc =
                       CRYPTODEV_BACKEND_GET_CLASS(backend);
 
-    if (bc->do_sym_op) {
-        return bc->do_sym_op(backend, op_info, queue_index, errp);
+    if (bc->do_op) {
+        return bc->do_op(backend, op_info, queue_index, errp);
     }
 
     return -VIRTIO_CRYPTO_ERR;
@@ -123,20 +123,18 @@ int cryptodev_backend_crypto_operation(
                  uint32_t queue_index, Error **errp)
 {
     VirtIOCryptoReq *req = opaque;
+    CryptoDevBackendOpInfo *op_info = &req->op_info;
+    enum CryptoDevBackendAlgType algtype = req->flags;
 
-    if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
-        CryptoDevBackendSymOpInfo *op_info;
-        op_info = req->u.sym_op_info;
-
-        return cryptodev_backend_sym_operation(backend,
-                         op_info, queue_index, errp);
-    } else {
+    if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
+        && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
         error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "",
-                   req->flags);
-       return -VIRTIO_CRYPTO_NOTSUPP;
+                   algtype);
+
+        return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    return -VIRTIO_CRYPTO_ERR;
+    return cryptodev_backend_operation(backend, op_info, queue_index, errp);
 }
 
 static void
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index dcd80b904d..fc1ca90202 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -83,7 +83,8 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
                struct iovec *iov, unsigned int out_num)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
-    CryptoDevBackendSymSessionInfo info;
+    CryptoDevBackendSessionInfo info;
+    CryptoDevBackendSymSessionInfo *sym_info;
     int64_t session_id;
     int queue_index;
     uint32_t op_type;
@@ -92,11 +93,13 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
 
     memset(&info, 0, sizeof(info));
     op_type = ldl_le_p(&sess_req->op_type);
-    info.op_type = op_type;
     info.op_code = opcode;
 
+    sym_info = &info.u.sym_sess_info;
+    sym_info->op_type = op_type;
+
     if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
-        ret = virtio_crypto_cipher_session_helper(vdev, &info,
+        ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
                            &sess_req->u.cipher.para,
                            &iov, &out_num);
         if (ret < 0) {
@@ -105,47 +108,47 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
         size_t s;
         /* cipher part */
-        ret = virtio_crypto_cipher_session_helper(vdev, &info,
+        ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
                            &sess_req->u.chain.para.cipher_param,
                            &iov, &out_num);
         if (ret < 0) {
             goto err;
         }
         /* hash part */
-        info.alg_chain_order = ldl_le_p(
+        sym_info->alg_chain_order = ldl_le_p(
                                      &sess_req->u.chain.para.alg_chain_order);
-        info.add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
-        info.hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
-        if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
-            info.hash_alg = ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
-            info.auth_key_len = ldl_le_p(
+        sym_info->add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
+        sym_info->hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
+        if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
+            sym_info->hash_alg =
+                ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
+            sym_info->auth_key_len = ldl_le_p(
                              &sess_req->u.chain.para.u.mac_param.auth_key_len);
-            info.hash_result_len = ldl_le_p(
+            sym_info->hash_result_len = ldl_le_p(
                            &sess_req->u.chain.para.u.mac_param.hash_result_len);
-            if (info.auth_key_len > vcrypto->conf.max_auth_key_len) {
+            if (sym_info->auth_key_len > vcrypto->conf.max_auth_key_len) {
                 error_report("virtio-crypto length of auth key is too big: %u",
-                             info.auth_key_len);
+                             sym_info->auth_key_len);
                 ret = -VIRTIO_CRYPTO_ERR;
                 goto err;
             }
             /* get auth key */
-            if (info.auth_key_len > 0) {
-                DPRINTF("auth_keylen=%" PRIu32 "\n", info.auth_key_len);
-                info.auth_key = g_malloc(info.auth_key_len);
-                s = iov_to_buf(iov, out_num, 0, info.auth_key,
-                               info.auth_key_len);
-                if (unlikely(s != info.auth_key_len)) {
+            if (sym_info->auth_key_len > 0) {
+                sym_info->auth_key = g_malloc(sym_info->auth_key_len);
+                s = iov_to_buf(iov, out_num, 0, sym_info->auth_key,
+                               sym_info->auth_key_len);
+                if (unlikely(s != sym_info->auth_key_len)) {
                     virtio_error(vdev,
                           "virtio-crypto authenticated key incorrect");
                     ret = -EFAULT;
                     goto err;
                 }
-                iov_discard_front(&iov, &out_num, info.auth_key_len);
+                iov_discard_front(&iov, &out_num, sym_info->auth_key_len);
             }
-        } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
-            info.hash_alg = ldl_le_p(
+        } else if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
+            sym_info->hash_alg = ldl_le_p(
                              &sess_req->u.chain.para.u.hash_param.algo);
-            info.hash_result_len = ldl_le_p(
+            sym_info->hash_result_len = ldl_le_p(
                         &sess_req->u.chain.para.u.hash_param.hash_result_len);
         } else {
             /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */
@@ -161,13 +164,10 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     }
 
     queue_index = virtio_crypto_vq2q(queue_id);
-    session_id = cryptodev_backend_sym_create_session(
+    session_id = cryptodev_backend_create_session(
                                      vcrypto->cryptodev,
                                      &info, queue_index, &local_err);
     if (session_id >= 0) {
-        DPRINTF("create session_id=%" PRIu64 " successfully\n",
-                session_id);
-
         ret = session_id;
     } else {
         if (local_err) {
@@ -177,11 +177,82 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     }
 
 err:
-    g_free(info.cipher_key);
-    g_free(info.auth_key);
+    g_free(sym_info->cipher_key);
+    g_free(sym_info->auth_key);
     return ret;
 }
 
+static int64_t
+virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto,
+               struct virtio_crypto_akcipher_create_session_req *sess_req,
+               uint32_t queue_id, uint32_t opcode,
+               struct iovec *iov, unsigned int out_num)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendSessionInfo info = {0};
+    CryptoDevBackendAsymSessionInfo *asym_info;
+    int64_t session_id;
+    int queue_index;
+    uint32_t algo, keytype, keylen;
+    uint8_t *key = NULL;
+    Error *local_err = NULL;
+
+    algo = ldl_le_p(&sess_req->para.algo);
+    keytype = ldl_le_p(&sess_req->para.keytype);
+    keylen = ldl_le_p(&sess_req->para.keylen);
+
+    if ((keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC)
+         && (keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE)) {
+        error_report("unsupported asym keytype: %d", keytype);
+        return -VIRTIO_CRYPTO_NOTSUPP;
+    }
+
+    if (keylen) {
+        key = g_malloc(keylen);
+        if (iov_to_buf(iov, out_num, 0, key, keylen) != keylen) {
+            virtio_error(vdev, "virtio-crypto asym key incorrect");
+            g_free(key);
+            return -EFAULT;
+        }
+        iov_discard_front(&iov, &out_num, keylen);
+    }
+
+    info.op_code = opcode;
+    asym_info = &info.u.asym_sess_info;
+    asym_info->algo = algo;
+    asym_info->keytype = keytype;
+    asym_info->keylen = keylen;
+    asym_info->key = key;
+    switch (asym_info->algo) {
+    case VIRTIO_CRYPTO_AKCIPHER_RSA:
+        asym_info->u.rsa.padding_algo =
+            ldl_le_p(&sess_req->para.u.rsa.padding_algo);
+        asym_info->u.rsa.hash_algo =
+            ldl_le_p(&sess_req->para.u.rsa.hash_algo);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+        asym_info->u.ecdsa.curve_id =
+            ldl_le_p(&sess_req->para.u.ecdsa.curve_id);
+        break;
+
+    default:
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    queue_index = virtio_crypto_vq2q(queue_id);
+    session_id = cryptodev_backend_create_session(vcrypto->cryptodev, &info,
+                     queue_index, &local_err);
+    if (session_id < 0) {
+        if (local_err) {
+            error_report_err(local_err);
+        }
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    return session_id;
+}
+
 static uint8_t
 virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
          struct virtio_crypto_destroy_session_req *close_sess_req,
@@ -193,9 +264,8 @@ virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
     Error *local_err = NULL;
 
     session_id = ldq_le_p(&close_sess_req->session_id);
-    DPRINTF("close session, id=%" PRIu64 "\n", session_id);
 
-    ret = cryptodev_backend_sym_close_session(
+    ret = cryptodev_backend_close_session(
               vcrypto->cryptodev, session_id, queue_id, &local_err);
     if (ret == 0) {
         status = VIRTIO_CRYPTO_OK;
@@ -260,13 +330,22 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         opcode = ldl_le_p(&ctrl.header.opcode);
         queue_id = ldl_le_p(&ctrl.header.queue_id);
 
+        memset(&input, 0, sizeof(input));
         switch (opcode) {
         case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
-            memset(&input, 0, sizeof(input));
             session_id = virtio_crypto_create_sym_session(vcrypto,
                              &ctrl.u.sym_create_session,
                              queue_id, opcode,
                              out_iov, out_num);
+            goto check_session;
+
+        case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+            session_id = virtio_crypto_create_asym_session(vcrypto,
+                             &ctrl.u.akcipher_create_session,
+                             queue_id, opcode,
+                             out_iov, out_num);
+
+check_session:
             /* Serious errors, need to reset virtio crypto device */
             if (session_id == -EFAULT) {
                 virtqueue_detach_element(vq, elem, 0);
@@ -290,10 +369,12 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
             virtqueue_push(vq, elem, sizeof(input));
             virtio_notify(vdev, vq);
             break;
+
         case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION:
         case VIRTIO_CRYPTO_HASH_DESTROY_SESSION:
         case VIRTIO_CRYPTO_MAC_DESTROY_SESSION:
         case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION:
+        case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION:
             status = virtio_crypto_handle_close_session(vcrypto,
                    &ctrl.u.destroy_session, queue_id);
             /* The status only occupy one byte, we can directly use it */
@@ -311,7 +392,6 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
         default:
             error_report("virtio-crypto unsupported ctrl opcode: %d", opcode);
-            memset(&input, 0, sizeof(input));
             stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP);
             s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input));
             if (unlikely(s != sizeof(input))) {
@@ -339,28 +419,37 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq,
     req->in_num = 0;
     req->in_len = 0;
     req->flags = CRYPTODEV_BACKEND_ALG__MAX;
-    req->u.sym_op_info = NULL;
+    memset(&req->op_info, 0x00, sizeof(req->op_info));
 }
 
 static void virtio_crypto_free_request(VirtIOCryptoReq *req)
 {
-    if (req) {
-        if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
-            size_t max_len;
-            CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info;
-
-            max_len = op_info->iv_len +
-                      op_info->aad_len +
-                      op_info->src_len +
-                      op_info->dst_len +
-                      op_info->digest_result_len;
-
-            /* Zeroize and free request data structure */
-            memset(op_info, 0, sizeof(*op_info) + max_len);
+    if (!req) {
+        return;
+    }
+
+    if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
+        size_t max_len;
+        CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
+
+        max_len = op_info->iv_len +
+                  op_info->aad_len +
+                  op_info->src_len +
+                  op_info->dst_len +
+                  op_info->digest_result_len;
+
+        /* Zeroize and free request data structure */
+        memset(op_info, 0, sizeof(*op_info) + max_len);
+        g_free(op_info);
+    } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+        CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
+        if (op_info) {
+            memset(op_info, 0, sizeof(*op_info));
             g_free(op_info);
         }
-        g_free(req);
     }
+
+    g_free(req);
 }
 
 static void
@@ -397,6 +486,35 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev,
     }
 }
 
+static void
+virtio_crypto_akcipher_input_data_helper(VirtIODevice *vdev,
+        VirtIOCryptoReq *req, int32_t status,
+        CryptoDevBackendAsymOpInfo *asym_op_info)
+{
+    size_t s, len;
+
+    if (status != VIRTIO_CRYPTO_OK) {
+        return;
+    }
+
+    len = asym_op_info->dst_len;
+    if (!len) {
+        return;
+    }
+
+    s = iov_from_buf(req->in_iov, req->in_num, 0, asym_op_info->dst, len);
+    if (s != len) {
+        virtio_error(vdev, "virtio-crypto asym dest data incorrect");
+        return;
+    }
+
+    iov_discard_front(&req->in_iov, &req->in_num, len);
+
+    /* For akcipher, dst_len may be changed after operation */
+    req->in_len = sizeof(struct virtio_crypto_inhdr) + asym_op_info->dst_len;
+}
+
+
 static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)
 {
     VirtIOCrypto *vcrypto = req->vcrypto;
@@ -404,7 +522,10 @@ static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)
 
     if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
         virtio_crypto_sym_input_data_helper(vdev, req, status,
-                                            req->u.sym_op_info);
+                                            req->op_info.u.sym_op_info);
+    } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+        virtio_crypto_akcipher_input_data_helper(vdev, req, status,
+                                             req->op_info.u.asym_op_info);
     }
     stb_p(&req->in->status, status);
     virtqueue_push(req->vq, &req->elem, req->in_len);
@@ -543,41 +664,100 @@ err:
 static int
 virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto,
                struct virtio_crypto_sym_data_req *req,
-               CryptoDevBackendSymOpInfo **sym_op_info,
+               CryptoDevBackendOpInfo *op_info,
                struct iovec *iov, unsigned int out_num)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendSymOpInfo *sym_op_info;
     uint32_t op_type;
-    CryptoDevBackendSymOpInfo *op_info;
 
     op_type = ldl_le_p(&req->op_type);
-
     if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
-        op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
+        sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
                                               NULL, iov, out_num);
-        if (!op_info) {
+        if (!sym_op_info) {
             return -EFAULT;
         }
-        op_info->op_type = op_type;
     } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
-        op_info = virtio_crypto_sym_op_helper(vdev, NULL,
+        sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL,
                                               &req->u.chain.para,
                                               iov, out_num);
-        if (!op_info) {
+        if (!sym_op_info) {
             return -EFAULT;
         }
-        op_info->op_type = op_type;
     } else {
         /* VIRTIO_CRYPTO_SYM_OP_NONE */
         error_report("virtio-crypto unsupported cipher type");
         return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    *sym_op_info = op_info;
+    sym_op_info->op_type = op_type;
+    op_info->u.sym_op_info = sym_op_info;
 
     return 0;
 }
 
+static int
+virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto,
+               struct virtio_crypto_akcipher_data_req *req,
+               CryptoDevBackendOpInfo *op_info,
+               struct iovec *iov, unsigned int out_num)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendAsymOpInfo *asym_op_info;
+    uint32_t src_len;
+    uint32_t dst_len;
+    uint32_t len;
+    uint8_t *src = NULL;
+    uint8_t *dst = NULL;
+
+    asym_op_info = g_malloc0(sizeof(CryptoDevBackendAsymOpInfo));
+    src_len = ldl_le_p(&req->para.src_data_len);
+    dst_len = ldl_le_p(&req->para.dst_data_len);
+
+    if (src_len > 0) {
+        src = g_malloc0(src_len);
+        len = iov_to_buf(iov, out_num, 0, src, src_len);
+        if (unlikely(len != src_len)) {
+            virtio_error(vdev, "virtio-crypto asym src data incorrect"
+                         "expected %u, actual %u", src_len, len);
+            goto err;
+        }
+
+        iov_discard_front(&iov, &out_num, src_len);
+    }
+
+    if (dst_len > 0) {
+        dst = g_malloc0(dst_len);
+
+        if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+            len = iov_to_buf(iov, out_num, 0, dst, dst_len);
+            if (unlikely(len != dst_len)) {
+                virtio_error(vdev, "virtio-crypto asym dst data incorrect"
+                             "expected %u, actual %u", dst_len, len);
+                goto err;
+            }
+
+            iov_discard_front(&iov, &out_num, dst_len);
+        }
+    }
+
+    asym_op_info->src_len = src_len;
+    asym_op_info->dst_len = dst_len;
+    asym_op_info->src = src;
+    asym_op_info->dst = dst;
+    op_info->u.asym_op_info = asym_op_info;
+
+    return 0;
+
+ err:
+    g_free(asym_op_info);
+    g_free(src);
+    g_free(dst);
+
+    return -EFAULT;
+}
+
 static int
 virtio_crypto_handle_request(VirtIOCryptoReq *request)
 {
@@ -595,8 +775,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
     unsigned out_num;
     uint32_t opcode;
     uint8_t status = VIRTIO_CRYPTO_ERR;
-    uint64_t session_id;
-    CryptoDevBackendSymOpInfo *sym_op_info = NULL;
+    CryptoDevBackendOpInfo *op_info = &request->op_info;
     Error *local_err = NULL;
 
     if (elem->out_num < 1 || elem->in_num < 1) {
@@ -639,15 +818,28 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
     request->in_iov = in_iov;
 
     opcode = ldl_le_p(&req.header.opcode);
-    session_id = ldq_le_p(&req.header.session_id);
+    op_info->session_id = ldq_le_p(&req.header.session_id);
+    op_info->op_code = opcode;
 
     switch (opcode) {
     case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
     case VIRTIO_CRYPTO_CIPHER_DECRYPT:
+        op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_SYM;
         ret = virtio_crypto_handle_sym_req(vcrypto,
-                         &req.u.sym_req,
-                         &sym_op_info,
+                         &req.u.sym_req, op_info,
+                         out_iov, out_num);
+        goto check_result;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+        op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_ASYM;
+        ret = virtio_crypto_handle_asym_req(vcrypto,
+                         &req.u.akcipher_req, op_info,
                          out_iov, out_num);
+
+check_result:
         /* Serious errors, need to reset virtio crypto device */
         if (ret == -EFAULT) {
             return -1;
@@ -655,11 +847,8 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
             virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP);
             virtio_crypto_free_request(request);
         } else {
-            sym_op_info->session_id = session_id;
 
             /* Set request's parameter */
-            request->flags = CRYPTODEV_BACKEND_ALG_SYM;
-            request->u.sym_op_info = sym_op_info;
             ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev,
                                     request, queue_index, &local_err);
             if (ret < 0) {
@@ -674,6 +863,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
             virtio_crypto_free_request(request);
         }
         break;
+
     case VIRTIO_CRYPTO_HASH:
     case VIRTIO_CRYPTO_MAC:
     case VIRTIO_CRYPTO_AEAD_ENCRYPT:
@@ -779,6 +969,7 @@ static void virtio_crypto_init_config(VirtIODevice *vdev)
     vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l;
     vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h;
     vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo;
+    vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo;
     vcrypto->conf.max_cipher_key_len =
                   vcrypto->conf.cryptodev->conf.max_cipher_key_len;
     vcrypto->conf.max_auth_key_len =
@@ -891,6 +1082,7 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config)
     stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len);
     stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len);
     stq_le_p(&crypto_cfg.max_size, c->conf.max_size);
+    stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo);
 
     memcpy(config, &crypto_cfg, c->config_size);
 }
diff --git a/include/hw/virtio/virtio-crypto.h b/include/hw/virtio/virtio-crypto.h
index a2228d7b2e..348749f5d5 100644
--- a/include/hw/virtio/virtio-crypto.h
+++ b/include/hw/virtio/virtio-crypto.h
@@ -50,6 +50,7 @@ typedef struct VirtIOCryptoConf {
     uint32_t mac_algo_l;
     uint32_t mac_algo_h;
     uint32_t aead_algo;
+    uint32_t akcipher_algo;
 
     /* Maximum length of cipher key */
     uint32_t max_cipher_key_len;
@@ -71,9 +72,7 @@ typedef struct VirtIOCryptoReq {
     size_t in_len;
     VirtQueue *vq;
     struct VirtIOCrypto *vcrypto;
-    union {
-        CryptoDevBackendSymOpInfo *sym_op_info;
-    } u;
+    CryptoDevBackendOpInfo op_info;
 } VirtIOCryptoReq;
 
 typedef struct VirtIOCryptoQueue {
diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h
index f4d4057d4d..b306775849 100644
--- a/include/sysemu/cryptodev.h
+++ b/include/sysemu/cryptodev.h
@@ -50,13 +50,13 @@ typedef struct CryptoDevBackendClient
 
 enum CryptoDevBackendAlgType {
     CRYPTODEV_BACKEND_ALG_SYM,
+    CRYPTODEV_BACKEND_ALG_ASYM,
     CRYPTODEV_BACKEND_ALG__MAX,
 };
 
 /**
  * CryptoDevBackendSymSessionInfo:
  *
- * @op_code: operation code (refer to virtio_crypto.h)
  * @cipher_alg: algorithm type of CIPHER
  * @key_len: byte length of cipher key
  * @hash_alg: algorithm type of HASH/MAC
@@ -74,7 +74,6 @@ enum CryptoDevBackendAlgType {
  */
 typedef struct CryptoDevBackendSymSessionInfo {
     /* corresponding with virtio crypto spec */
-    uint32_t op_code;
     uint32_t cipher_alg;
     uint32_t key_len;
     uint32_t hash_alg;
@@ -89,11 +88,41 @@ typedef struct CryptoDevBackendSymSessionInfo {
     uint8_t *auth_key;
 } CryptoDevBackendSymSessionInfo;
 
+/**
+ * CryptoDevBackendAsymSessionInfo:
+ */
+typedef struct CryptoDevBackendRsaPara {
+    uint32_t padding_algo;
+    uint32_t hash_algo;
+} CryptoDevBackendRsaPara;
+
+typedef struct CryptoDevBackendEcdsaPara {
+    uint32_t curve_id;
+} CryptoDevBackendEcdsaPara;
+
+typedef struct CryptoDevBackendAsymSessionInfo {
+    /* corresponding with virtio crypto spec */
+    uint32_t algo;
+    uint32_t keytype;
+    uint32_t keylen;
+    uint8_t *key;
+    union {
+        CryptoDevBackendRsaPara rsa;
+        CryptoDevBackendEcdsaPara ecdsa;
+    } u;
+} CryptoDevBackendAsymSessionInfo;
+
+typedef struct CryptoDevBackendSessionInfo {
+    uint32_t op_code;
+    union {
+        CryptoDevBackendSymSessionInfo sym_sess_info;
+        CryptoDevBackendAsymSessionInfo asym_sess_info;
+    } u;
+} CryptoDevBackendSessionInfo;
+
 /**
  * CryptoDevBackendSymOpInfo:
  *
- * @session_id: session index which was previously
- *              created by cryptodev_backend_sym_create_session()
  * @aad_len: byte length of additional authenticated data
  * @iv_len: byte length of initialization vector or counter
  * @src_len: byte length of source data
@@ -119,7 +148,6 @@ typedef struct CryptoDevBackendSymSessionInfo {
  *
  */
 typedef struct CryptoDevBackendSymOpInfo {
-    uint64_t session_id;
     uint32_t aad_len;
     uint32_t iv_len;
     uint32_t src_len;
@@ -138,6 +166,33 @@ typedef struct CryptoDevBackendSymOpInfo {
     uint8_t data[];
 } CryptoDevBackendSymOpInfo;
 
+
+/**
+ * CryptoDevBackendAsymOpInfo:
+ *
+ * @src_len: byte length of source data
+ * @dst_len: byte length of destination data
+ * @src: point to the source data
+ * @dst: point to the destination data
+ *
+ */
+typedef struct CryptoDevBackendAsymOpInfo {
+    uint32_t src_len;
+    uint32_t dst_len;
+    uint8_t *src;
+    uint8_t *dst;
+} CryptoDevBackendAsymOpInfo;
+
+typedef struct CryptoDevBackendOpInfo {
+    enum CryptoDevBackendAlgType algtype;
+    uint32_t op_code;
+    uint64_t session_id;
+    union {
+        CryptoDevBackendSymOpInfo *sym_op_info;
+        CryptoDevBackendAsymOpInfo *asym_op_info;
+    } u;
+} CryptoDevBackendOpInfo;
+
 struct CryptoDevBackendClass {
     ObjectClass parent_class;
 
@@ -145,13 +200,13 @@ struct CryptoDevBackendClass {
     void (*cleanup)(CryptoDevBackend *backend, Error **errp);
 
     int64_t (*create_session)(CryptoDevBackend *backend,
-                       CryptoDevBackendSymSessionInfo *sess_info,
+                       CryptoDevBackendSessionInfo *sess_info,
                        uint32_t queue_index, Error **errp);
     int (*close_session)(CryptoDevBackend *backend,
                            uint64_t session_id,
                            uint32_t queue_index, Error **errp);
-    int (*do_sym_op)(CryptoDevBackend *backend,
-                     CryptoDevBackendSymOpInfo *op_info,
+    int (*do_op)(CryptoDevBackend *backend,
+                     CryptoDevBackendOpInfo *op_info,
                      uint32_t queue_index, Error **errp);
 };
 
@@ -190,6 +245,7 @@ struct CryptoDevBackendConf {
     uint32_t mac_algo_l;
     uint32_t mac_algo_h;
     uint32_t aead_algo;
+    uint32_t akcipher_algo;
     /* Maximum length of cipher key */
     uint32_t max_cipher_key_len;
     /* Maximum length of authenticated key */
@@ -247,34 +303,34 @@ void cryptodev_backend_cleanup(
            Error **errp);
 
 /**
- * cryptodev_backend_sym_create_session:
+ * cryptodev_backend_create_session:
  * @backend: the cryptodev backend object
  * @sess_info: parameters needed by session creating
  * @queue_index: queue index of cryptodev backend client
  * @errp: pointer to a NULL-initialized error object
  *
- * Create a session for symmetric algorithms
+ * Create a session for symmetric/symmetric algorithms
  *
  * Returns: session id on success, or -1 on error
  */
-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp);
 
 /**
- * cryptodev_backend_sym_close_session:
+ * cryptodev_backend_close_session:
  * @backend: the cryptodev backend object
  * @session_id: the session id
  * @queue_index: queue index of cryptodev backend client
  * @errp: pointer to a NULL-initialized error object
  *
- * Close a session for symmetric algorithms which was previously
- * created by cryptodev_backend_sym_create_session()
+ * Close a session for which was previously
+ * created by cryptodev_backend_create_session()
  *
  * Returns: 0 on success, or Negative on error
  */
-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 62+ messages in thread

* [PATCH v3 6/6] virtio-crypto: Introduce RSA algorithm
@ 2022-03-23  2:49   ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  2:49 UTC (permalink / raw)
  To: arei.gonglei, mst
  Cc: herbert, jasowang, qemu-devel, zhenwei pi, virtualization, linux-crypto

There are two parts in this patch:
1, support akcipher service by cryptodev-builtin driver
2, virtio-crypto driver supports akcipher service

Then virtio-crypto gets request from guest side, and forwards the
request to builtin driver to handle it.

Test with a guest linux:
1, The self-test framework of crypto layer works fine in guest kernel
2, Test with Linux guest(with asym support), the following script
test(note that pkey_XXX is supported only in a newer version of keyutils):
  - both public key & private key
  - create/close session
  - encrypt/decrypt/sign/verify basic driver operation
  - also test with kernel crypto layer(pkey add/query)

All the cases work fine.

Run script in guest:
rm -rf *.der *.pem *.pfx
modprobe pkcs8_key_parser # if CONFIG_PKCS8_PRIVATE_KEY_PARSER=m
rm -rf /tmp/data
dd if=/dev/random of=/tmp/data count=1 bs=226

openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -subj "/C=CN/ST=BJ/L=HD/O=qemu/OU=dev/CN=qemu/emailAddress=qemu@qemu.org"
openssl pkcs8 -in key.pem -topk8 -nocrypt -outform DER -out key.der
openssl x509 -in cert.pem -inform PEM -outform DER -out cert.der

PRIV_KEY_ID=`cat key.der | keyctl padd asymmetric test_priv_key @s`
echo "priv key id = "$PRIV_KEY_ID
PUB_KEY_ID=`cat cert.der | keyctl padd asymmetric test_pub_key @s`
echo "pub key id = "$PUB_KEY_ID

keyctl pkey_query $PRIV_KEY_ID 0
keyctl pkey_query $PUB_KEY_ID 0

echo "Enc with priv key..."
keyctl pkey_encrypt $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.priv
echo "Dec with pub key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.priv enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Sign with priv key..."
keyctl pkey_sign $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 hash=sha1 > /tmp/sig
echo "Verify with pub key..."
keyctl pkey_verify $PRIV_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

echo "Enc with pub key..."
keyctl pkey_encrypt $PUB_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.pub
echo "Dec with priv key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.pub enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Verify with pub key..."
keyctl pkey_verify $PUB_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

Co-developed-by: lei he <helei.sig11@bytedance.com
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Signed-off-by: lei he <helei.sig11@bytedance.com
---
 backends/cryptodev-builtin.c      | 319 +++++++++++++++++++++++++----
 backends/cryptodev-vhost-user.c   |  34 +++-
 backends/cryptodev.c              |  32 ++-
 hw/virtio/virtio-crypto.c         | 326 ++++++++++++++++++++++++------
 include/hw/virtio/virtio-crypto.h |   5 +-
 include/sysemu/cryptodev.h        |  88 ++++++--
 6 files changed, 660 insertions(+), 144 deletions(-)

diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 0671bf9f3e..bae12c7068 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -26,6 +26,7 @@
 #include "qapi/error.h"
 #include "standard-headers/linux/virtio_crypto.h"
 #include "crypto/cipher.h"
+#include "crypto/akcipher.h"
 #include "qom/object.h"
 
 
@@ -41,11 +42,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
 typedef struct CryptoDevBackendBuiltinSession {
     QCryptoCipher *cipher;
     uint8_t direction; /* encryption or decryption */
-    uint8_t type; /* cipher? hash? aead? */
+    uint8_t type; /* cipher? hash? aead? akcipher? */
+    QCryptoAkcipher *akcipher;
     QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
 } CryptoDevBackendBuiltinSession;
 
-/* Max number of symmetric sessions */
+/* Max number of symmetric/asymmetric sessions */
 #define MAX_NUM_SESSIONS 256
 
 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN    512
@@ -80,15 +82,17 @@ static void cryptodev_builtin_init(
     backend->conf.crypto_services =
                          1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
                          1u << VIRTIO_CRYPTO_SERVICE_HASH |
-                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
+                         1u << VIRTIO_CRYPTO_SERVICE_MAC |
+                         1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
     backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
     backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
+    backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
     /*
      * Set the Maximum length of crypto request.
      * Why this value? Just avoid to overflow when
      * memory allocation for each crypto request.
      */
-    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
+    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
     backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
     backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
 
@@ -148,6 +152,100 @@ err:
    return -1;
 }
 
+static int cryptodev_builtin_get_rsa_hash_algo(
+    int virtio_rsa_hash, Error **errp)
+{
+    switch (virtio_rsa_hash) {
+    case VIRTIO_CRYPTO_RSA_MD2:
+        return QCRYPTO_RSA_HASH_ALG_MD2;
+
+    case VIRTIO_CRYPTO_RSA_MD3:
+        return QCRYPTO_RSA_HASH_ALG_MD3;
+
+    case VIRTIO_CRYPTO_RSA_MD4:
+        return QCRYPTO_RSA_HASH_ALG_MD4;
+
+    case VIRTIO_CRYPTO_RSA_MD5:
+        return QCRYPTO_RSA_HASH_ALG_MD5;
+
+    case VIRTIO_CRYPTO_RSA_SHA1:
+        return QCRYPTO_RSA_HASH_ALG_SHA1;
+
+    case VIRTIO_CRYPTO_RSA_SHA256:
+        return QCRYPTO_RSA_HASH_ALG_SHA256;
+
+    case VIRTIO_CRYPTO_RSA_SHA384:
+        return QCRYPTO_RSA_HASH_ALG_SHA384;
+
+    case VIRTIO_CRYPTO_RSA_SHA512:
+        return QCRYPTO_RSA_HASH_ALG_SHA512;
+
+    case VIRTIO_CRYPTO_RSA_SHA224:
+        return QCRYPTO_RSA_HASH_ALG_SHA224;
+
+    default:
+        error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
+        return -1;
+    }
+}
+
+static int cryptodev_builtin_set_rsa_options(
+                    int virtio_padding_algo,
+                    int virtio_hash_algo,
+                    QCryptoRsaOptions *opt,
+                    Error **errp)
+{
+    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
+        opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1;
+        opt->hash_algo =
+            cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
+        if (opt->hash_algo < 0) {
+            return -1;
+        }
+        return 0;
+    }
+
+    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
+        opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW;
+        return 0;
+    }
+
+    error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
+    return -1;
+}
+
+static int cryptodev_builtin_set_ecdsa_options(int virtio_curve_id,
+                    QCryptoEcdsaOptions *opt, Error **errp)
+{
+    switch (virtio_curve_id) {
+    case VIRTIO_CRYPTO_CURVE_NIST_P192:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P192;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P224:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P224;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P256:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P256;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P384:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P384;
+        break;
+
+    case VIRTIO_CRYPTO_CURVE_NIST_P521:
+        opt->curve_id = QCRYPTO_CURVE_ID_NIST_P521;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported curve id: %d", virtio_curve_id);
+        return -1;
+    }
+
+    return 0;
+}
+
 static int cryptodev_builtin_create_cipher_session(
                     CryptoDevBackendBuiltin *builtin,
                     CryptoDevBackendSymSessionInfo *sess_info,
@@ -240,26 +338,100 @@ static int cryptodev_builtin_create_cipher_session(
     return index;
 }
 
-static int64_t cryptodev_builtin_sym_create_session(
+static int cryptodev_builtin_create_akcipher_session(
+                    CryptoDevBackendBuiltin *builtin,
+                    CryptoDevBackendAsymSessionInfo *sess_info,
+                    Error **errp)
+{
+    CryptoDevBackendBuiltinSession *sess;
+    QCryptoAkcipher *akcipher;
+    int index;
+    QCryptoAkcipherAlgorithm alg;
+    QCryptoAkcipherKeyType type;
+    QCryptoRsaOptions rsa_opt;
+    QCryptoEcdsaOptions ecdsa_opt;
+    void *opt;
+
+    switch (sess_info->algo) {
+    case VIRTIO_CRYPTO_AKCIPHER_RSA:
+        alg = QCRYPTO_AKCIPHER_ALG_RSA;
+        if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
+            sess_info->u.rsa.hash_algo, &rsa_opt, errp) != 0) {
+            return -1;
+        }
+        opt = (void *)&rsa_opt;
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+        alg = QCRYPTO_AKCIPHER_ALG_ECDSA;
+        if (cryptodev_builtin_set_ecdsa_options(sess_info->u.ecdsa.curve_id,
+            &ecdsa_opt, errp) != 0) {
+            return -1;
+        }
+        opt = (void *)&ecdsa_opt;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
+        return -1;
+    }
+
+    switch (sess_info->keytype) {
+    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+        type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+        type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
+        break;
+
+    default:
+        error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
+        return -1;
+    }
+
+    index = cryptodev_builtin_get_unused_session_index(builtin);
+    if (index < 0) {
+        error_setg(errp, "Total number of sessions created exceeds %u",
+                   MAX_NUM_SESSIONS);
+        return -1;
+    }
+
+    akcipher = qcrypto_akcipher_new(alg, type, sess_info->key,
+                                    sess_info->keylen, opt, errp);
+    if (!akcipher) {
+        return -1;
+    }
+
+    sess = g_new0(CryptoDevBackendBuiltinSession, 1);
+    sess->akcipher = akcipher;
+
+    builtin->sessions[index] = sess;
+
+    return index;
+}
+
+static int64_t cryptodev_builtin_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendBuiltin *builtin =
                       CRYPTODEV_BACKEND_BUILTIN(backend);
-    int64_t session_id = -1;
-    int ret;
+    CryptoDevBackendSymSessionInfo *sym_sess_info;
+    CryptoDevBackendAsymSessionInfo *asym_sess_info;
 
     switch (sess_info->op_code) {
     case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
-        ret = cryptodev_builtin_create_cipher_session(
-                           builtin, sess_info, errp);
-        if (ret < 0) {
-            return ret;
-        } else {
-            session_id = ret;
-        }
-        break;
+        sym_sess_info = &sess_info->u.sym_sess_info;
+        return cryptodev_builtin_create_cipher_session(
+                           builtin, sym_sess_info, errp);
+
+    case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+        asym_sess_info = &sess_info->u.asym_sess_info;
+        return cryptodev_builtin_create_akcipher_session(
+                           builtin, asym_sess_info, errp);
+
     case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
     case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
     default:
@@ -268,10 +440,10 @@ static int64_t cryptodev_builtin_sym_create_session(
         return -1;
     }
 
-    return session_id;
+    return -1;
 }
 
-static int cryptodev_builtin_sym_close_session(
+static int cryptodev_builtin_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -288,30 +460,17 @@ static int cryptodev_builtin_sym_close_session(
 }
 
 static int cryptodev_builtin_sym_operation(
-                 CryptoDevBackend *backend,
-                 CryptoDevBackendSymOpInfo *op_info,
-                 uint32_t queue_index, Error **errp)
+                 CryptoDevBackendBuiltinSession *sess,
+                 CryptoDevBackendSymOpInfo *op_info, Error **errp)
 {
-    CryptoDevBackendBuiltin *builtin =
-                      CRYPTODEV_BACKEND_BUILTIN(backend);
-    CryptoDevBackendBuiltinSession *sess;
     int ret;
 
-    if (op_info->session_id >= MAX_NUM_SESSIONS ||
-              builtin->sessions[op_info->session_id] == NULL) {
-        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
-                   op_info->session_id);
-        return -VIRTIO_CRYPTO_INVSESS;
-    }
-
     if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
         error_setg(errp,
                "Algorithm chain is unsupported for cryptdoev-builtin");
         return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    sess = builtin->sessions[op_info->session_id];
-
     if (op_info->iv_len > 0) {
         ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
                                    op_info->iv_len, errp);
@@ -333,9 +492,95 @@ static int cryptodev_builtin_sym_operation(
             return -VIRTIO_CRYPTO_ERR;
         }
     }
+
+    return VIRTIO_CRYPTO_OK;
+}
+
+static int cryptodev_builtin_asym_operation(
+                 CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
+                 CryptoDevBackendAsymOpInfo *op_info, Error **errp)
+{
+    int ret;
+
+    switch (op_code) {
+    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+        ret = qcrypto_akcipher_encrypt(sess->akcipher,
+                                       op_info->src, op_info->src_len,
+                                       op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+        ret = qcrypto_akcipher_decrypt(sess->akcipher,
+                                       op_info->src, op_info->src_len,
+                                       op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+        ret = qcrypto_akcipher_sign(sess->akcipher,
+                                    op_info->src, op_info->src_len,
+                                    op_info->dst, op_info->dst_len, errp);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+        ret = qcrypto_akcipher_verify(sess->akcipher,
+                                      op_info->src, op_info->src_len,
+                                      op_info->dst, op_info->dst_len, errp);
+    break;
+
+    default:
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    if (ret < 0) {
+        if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+            return -VIRTIO_CRYPTO_KEY_REJECTED;
+        }
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    /* Buffer is too short */
+    if (unlikely(ret > op_info->dst_len)) {
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    op_info->dst_len = ret;
+
     return VIRTIO_CRYPTO_OK;
 }
 
+static int cryptodev_builtin_operation(
+                 CryptoDevBackend *backend,
+                 CryptoDevBackendOpInfo *op_info,
+                 uint32_t queue_index, Error **errp)
+{
+    CryptoDevBackendBuiltin *builtin =
+                      CRYPTODEV_BACKEND_BUILTIN(backend);
+    CryptoDevBackendBuiltinSession *sess;
+    CryptoDevBackendSymOpInfo *sym_op_info;
+    CryptoDevBackendAsymOpInfo *asym_op_info;
+    enum CryptoDevBackendAlgType algtype = op_info->algtype;
+    int ret = -VIRTIO_CRYPTO_ERR;
+
+    if (op_info->session_id >= MAX_NUM_SESSIONS ||
+              builtin->sessions[op_info->session_id] == NULL) {
+        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
+                   op_info->session_id);
+        return -VIRTIO_CRYPTO_INVSESS;
+    }
+
+    sess = builtin->sessions[op_info->session_id];
+    if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
+        sym_op_info = op_info->u.sym_op_info;
+        ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp);
+    } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
+        asym_op_info = op_info->u.asym_op_info;
+        ret = cryptodev_builtin_asym_operation(sess, op_info->op_code,
+                                               asym_op_info, errp);
+    }
+
+    return ret;
+}
+
 static void cryptodev_builtin_cleanup(
              CryptoDevBackend *backend,
              Error **errp)
@@ -348,7 +593,7 @@ static void cryptodev_builtin_cleanup(
 
     for (i = 0; i < MAX_NUM_SESSIONS; i++) {
         if (builtin->sessions[i] != NULL) {
-            cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort);
+            cryptodev_builtin_close_session(backend, i, 0, &error_abort);
         }
     }
 
@@ -370,9 +615,9 @@ cryptodev_builtin_class_init(ObjectClass *oc, void *data)
 
     bc->init = cryptodev_builtin_init;
     bc->cleanup = cryptodev_builtin_cleanup;
-    bc->create_session = cryptodev_builtin_sym_create_session;
-    bc->close_session = cryptodev_builtin_sym_close_session;
-    bc->do_sym_op = cryptodev_builtin_sym_operation;
+    bc->create_session = cryptodev_builtin_create_session;
+    bc->close_session = cryptodev_builtin_close_session;
+    bc->do_op = cryptodev_builtin_operation;
 }
 
 static const TypeInfo cryptodev_builtin_info = {
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index bedb452474..5443a59153 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -259,7 +259,33 @@ static int64_t cryptodev_vhost_user_sym_create_session(
     return -1;
 }
 
-static int cryptodev_vhost_user_sym_close_session(
+static int64_t cryptodev_vhost_user_create_session(
+           CryptoDevBackend *backend,
+           CryptoDevBackendSessionInfo *sess_info,
+           uint32_t queue_index, Error **errp)
+{
+    uint32_t op_code = sess_info->op_code;
+    CryptoDevBackendSymSessionInfo *sym_sess_info;
+
+    switch (op_code) {
+    case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
+    case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
+    case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
+    case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
+        sym_sess_info = &sess_info->u.sym_sess_info;
+        return cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
+                   queue_index, errp);
+    default:
+        error_setg(errp, "Unsupported opcode :%" PRIu32 "",
+                   sess_info->op_code);
+        return -1;
+
+    }
+
+    return -1;
+}
+
+static int cryptodev_vhost_user_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -351,9 +377,9 @@ cryptodev_vhost_user_class_init(ObjectClass *oc, void *data)
 
     bc->init = cryptodev_vhost_user_init;
     bc->cleanup = cryptodev_vhost_user_cleanup;
-    bc->create_session = cryptodev_vhost_user_sym_create_session;
-    bc->close_session = cryptodev_vhost_user_sym_close_session;
-    bc->do_sym_op = NULL;
+    bc->create_session = cryptodev_vhost_user_create_session;
+    bc->close_session = cryptodev_vhost_user_close_session;
+    bc->do_op = NULL;
 
     object_class_property_add_str(oc, "chardev",
                                   cryptodev_vhost_user_get_chardev,
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 2b105e433c..33eb4e1a70 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -72,9 +72,9 @@ void cryptodev_backend_cleanup(
     }
 }
 
-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendClass *bc =
@@ -87,7 +87,7 @@ int64_t cryptodev_backend_sym_create_session(
     return -1;
 }
 
-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp)
@@ -102,16 +102,16 @@ int cryptodev_backend_sym_close_session(
     return -1;
 }
 
-static int cryptodev_backend_sym_operation(
+static int cryptodev_backend_operation(
                  CryptoDevBackend *backend,
-                 CryptoDevBackendSymOpInfo *op_info,
+                 CryptoDevBackendOpInfo *op_info,
                  uint32_t queue_index, Error **errp)
 {
     CryptoDevBackendClass *bc =
                       CRYPTODEV_BACKEND_GET_CLASS(backend);
 
-    if (bc->do_sym_op) {
-        return bc->do_sym_op(backend, op_info, queue_index, errp);
+    if (bc->do_op) {
+        return bc->do_op(backend, op_info, queue_index, errp);
     }
 
     return -VIRTIO_CRYPTO_ERR;
@@ -123,20 +123,18 @@ int cryptodev_backend_crypto_operation(
                  uint32_t queue_index, Error **errp)
 {
     VirtIOCryptoReq *req = opaque;
+    CryptoDevBackendOpInfo *op_info = &req->op_info;
+    enum CryptoDevBackendAlgType algtype = req->flags;
 
-    if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
-        CryptoDevBackendSymOpInfo *op_info;
-        op_info = req->u.sym_op_info;
-
-        return cryptodev_backend_sym_operation(backend,
-                         op_info, queue_index, errp);
-    } else {
+    if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
+        && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
         error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "",
-                   req->flags);
-       return -VIRTIO_CRYPTO_NOTSUPP;
+                   algtype);
+
+        return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    return -VIRTIO_CRYPTO_ERR;
+    return cryptodev_backend_operation(backend, op_info, queue_index, errp);
 }
 
 static void
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index dcd80b904d..fc1ca90202 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -83,7 +83,8 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
                struct iovec *iov, unsigned int out_num)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
-    CryptoDevBackendSymSessionInfo info;
+    CryptoDevBackendSessionInfo info;
+    CryptoDevBackendSymSessionInfo *sym_info;
     int64_t session_id;
     int queue_index;
     uint32_t op_type;
@@ -92,11 +93,13 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
 
     memset(&info, 0, sizeof(info));
     op_type = ldl_le_p(&sess_req->op_type);
-    info.op_type = op_type;
     info.op_code = opcode;
 
+    sym_info = &info.u.sym_sess_info;
+    sym_info->op_type = op_type;
+
     if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
-        ret = virtio_crypto_cipher_session_helper(vdev, &info,
+        ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
                            &sess_req->u.cipher.para,
                            &iov, &out_num);
         if (ret < 0) {
@@ -105,47 +108,47 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
         size_t s;
         /* cipher part */
-        ret = virtio_crypto_cipher_session_helper(vdev, &info,
+        ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
                            &sess_req->u.chain.para.cipher_param,
                            &iov, &out_num);
         if (ret < 0) {
             goto err;
         }
         /* hash part */
-        info.alg_chain_order = ldl_le_p(
+        sym_info->alg_chain_order = ldl_le_p(
                                      &sess_req->u.chain.para.alg_chain_order);
-        info.add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
-        info.hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
-        if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
-            info.hash_alg = ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
-            info.auth_key_len = ldl_le_p(
+        sym_info->add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
+        sym_info->hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
+        if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
+            sym_info->hash_alg =
+                ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
+            sym_info->auth_key_len = ldl_le_p(
                              &sess_req->u.chain.para.u.mac_param.auth_key_len);
-            info.hash_result_len = ldl_le_p(
+            sym_info->hash_result_len = ldl_le_p(
                            &sess_req->u.chain.para.u.mac_param.hash_result_len);
-            if (info.auth_key_len > vcrypto->conf.max_auth_key_len) {
+            if (sym_info->auth_key_len > vcrypto->conf.max_auth_key_len) {
                 error_report("virtio-crypto length of auth key is too big: %u",
-                             info.auth_key_len);
+                             sym_info->auth_key_len);
                 ret = -VIRTIO_CRYPTO_ERR;
                 goto err;
             }
             /* get auth key */
-            if (info.auth_key_len > 0) {
-                DPRINTF("auth_keylen=%" PRIu32 "\n", info.auth_key_len);
-                info.auth_key = g_malloc(info.auth_key_len);
-                s = iov_to_buf(iov, out_num, 0, info.auth_key,
-                               info.auth_key_len);
-                if (unlikely(s != info.auth_key_len)) {
+            if (sym_info->auth_key_len > 0) {
+                sym_info->auth_key = g_malloc(sym_info->auth_key_len);
+                s = iov_to_buf(iov, out_num, 0, sym_info->auth_key,
+                               sym_info->auth_key_len);
+                if (unlikely(s != sym_info->auth_key_len)) {
                     virtio_error(vdev,
                           "virtio-crypto authenticated key incorrect");
                     ret = -EFAULT;
                     goto err;
                 }
-                iov_discard_front(&iov, &out_num, info.auth_key_len);
+                iov_discard_front(&iov, &out_num, sym_info->auth_key_len);
             }
-        } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
-            info.hash_alg = ldl_le_p(
+        } else if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
+            sym_info->hash_alg = ldl_le_p(
                              &sess_req->u.chain.para.u.hash_param.algo);
-            info.hash_result_len = ldl_le_p(
+            sym_info->hash_result_len = ldl_le_p(
                         &sess_req->u.chain.para.u.hash_param.hash_result_len);
         } else {
             /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */
@@ -161,13 +164,10 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     }
 
     queue_index = virtio_crypto_vq2q(queue_id);
-    session_id = cryptodev_backend_sym_create_session(
+    session_id = cryptodev_backend_create_session(
                                      vcrypto->cryptodev,
                                      &info, queue_index, &local_err);
     if (session_id >= 0) {
-        DPRINTF("create session_id=%" PRIu64 " successfully\n",
-                session_id);
-
         ret = session_id;
     } else {
         if (local_err) {
@@ -177,11 +177,82 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
     }
 
 err:
-    g_free(info.cipher_key);
-    g_free(info.auth_key);
+    g_free(sym_info->cipher_key);
+    g_free(sym_info->auth_key);
     return ret;
 }
 
+static int64_t
+virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto,
+               struct virtio_crypto_akcipher_create_session_req *sess_req,
+               uint32_t queue_id, uint32_t opcode,
+               struct iovec *iov, unsigned int out_num)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendSessionInfo info = {0};
+    CryptoDevBackendAsymSessionInfo *asym_info;
+    int64_t session_id;
+    int queue_index;
+    uint32_t algo, keytype, keylen;
+    uint8_t *key = NULL;
+    Error *local_err = NULL;
+
+    algo = ldl_le_p(&sess_req->para.algo);
+    keytype = ldl_le_p(&sess_req->para.keytype);
+    keylen = ldl_le_p(&sess_req->para.keylen);
+
+    if ((keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC)
+         && (keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE)) {
+        error_report("unsupported asym keytype: %d", keytype);
+        return -VIRTIO_CRYPTO_NOTSUPP;
+    }
+
+    if (keylen) {
+        key = g_malloc(keylen);
+        if (iov_to_buf(iov, out_num, 0, key, keylen) != keylen) {
+            virtio_error(vdev, "virtio-crypto asym key incorrect");
+            g_free(key);
+            return -EFAULT;
+        }
+        iov_discard_front(&iov, &out_num, keylen);
+    }
+
+    info.op_code = opcode;
+    asym_info = &info.u.asym_sess_info;
+    asym_info->algo = algo;
+    asym_info->keytype = keytype;
+    asym_info->keylen = keylen;
+    asym_info->key = key;
+    switch (asym_info->algo) {
+    case VIRTIO_CRYPTO_AKCIPHER_RSA:
+        asym_info->u.rsa.padding_algo =
+            ldl_le_p(&sess_req->para.u.rsa.padding_algo);
+        asym_info->u.rsa.hash_algo =
+            ldl_le_p(&sess_req->para.u.rsa.hash_algo);
+        break;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+        asym_info->u.ecdsa.curve_id =
+            ldl_le_p(&sess_req->para.u.ecdsa.curve_id);
+        break;
+
+    default:
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    queue_index = virtio_crypto_vq2q(queue_id);
+    session_id = cryptodev_backend_create_session(vcrypto->cryptodev, &info,
+                     queue_index, &local_err);
+    if (session_id < 0) {
+        if (local_err) {
+            error_report_err(local_err);
+        }
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    return session_id;
+}
+
 static uint8_t
 virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
          struct virtio_crypto_destroy_session_req *close_sess_req,
@@ -193,9 +264,8 @@ virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
     Error *local_err = NULL;
 
     session_id = ldq_le_p(&close_sess_req->session_id);
-    DPRINTF("close session, id=%" PRIu64 "\n", session_id);
 
-    ret = cryptodev_backend_sym_close_session(
+    ret = cryptodev_backend_close_session(
               vcrypto->cryptodev, session_id, queue_id, &local_err);
     if (ret == 0) {
         status = VIRTIO_CRYPTO_OK;
@@ -260,13 +330,22 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         opcode = ldl_le_p(&ctrl.header.opcode);
         queue_id = ldl_le_p(&ctrl.header.queue_id);
 
+        memset(&input, 0, sizeof(input));
         switch (opcode) {
         case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
-            memset(&input, 0, sizeof(input));
             session_id = virtio_crypto_create_sym_session(vcrypto,
                              &ctrl.u.sym_create_session,
                              queue_id, opcode,
                              out_iov, out_num);
+            goto check_session;
+
+        case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+            session_id = virtio_crypto_create_asym_session(vcrypto,
+                             &ctrl.u.akcipher_create_session,
+                             queue_id, opcode,
+                             out_iov, out_num);
+
+check_session:
             /* Serious errors, need to reset virtio crypto device */
             if (session_id == -EFAULT) {
                 virtqueue_detach_element(vq, elem, 0);
@@ -290,10 +369,12 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
             virtqueue_push(vq, elem, sizeof(input));
             virtio_notify(vdev, vq);
             break;
+
         case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION:
         case VIRTIO_CRYPTO_HASH_DESTROY_SESSION:
         case VIRTIO_CRYPTO_MAC_DESTROY_SESSION:
         case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION:
+        case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION:
             status = virtio_crypto_handle_close_session(vcrypto,
                    &ctrl.u.destroy_session, queue_id);
             /* The status only occupy one byte, we can directly use it */
@@ -311,7 +392,6 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
         default:
             error_report("virtio-crypto unsupported ctrl opcode: %d", opcode);
-            memset(&input, 0, sizeof(input));
             stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP);
             s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input));
             if (unlikely(s != sizeof(input))) {
@@ -339,28 +419,37 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq,
     req->in_num = 0;
     req->in_len = 0;
     req->flags = CRYPTODEV_BACKEND_ALG__MAX;
-    req->u.sym_op_info = NULL;
+    memset(&req->op_info, 0x00, sizeof(req->op_info));
 }
 
 static void virtio_crypto_free_request(VirtIOCryptoReq *req)
 {
-    if (req) {
-        if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
-            size_t max_len;
-            CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info;
-
-            max_len = op_info->iv_len +
-                      op_info->aad_len +
-                      op_info->src_len +
-                      op_info->dst_len +
-                      op_info->digest_result_len;
-
-            /* Zeroize and free request data structure */
-            memset(op_info, 0, sizeof(*op_info) + max_len);
+    if (!req) {
+        return;
+    }
+
+    if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
+        size_t max_len;
+        CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
+
+        max_len = op_info->iv_len +
+                  op_info->aad_len +
+                  op_info->src_len +
+                  op_info->dst_len +
+                  op_info->digest_result_len;
+
+        /* Zeroize and free request data structure */
+        memset(op_info, 0, sizeof(*op_info) + max_len);
+        g_free(op_info);
+    } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+        CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
+        if (op_info) {
+            memset(op_info, 0, sizeof(*op_info));
             g_free(op_info);
         }
-        g_free(req);
     }
+
+    g_free(req);
 }
 
 static void
@@ -397,6 +486,35 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev,
     }
 }
 
+static void
+virtio_crypto_akcipher_input_data_helper(VirtIODevice *vdev,
+        VirtIOCryptoReq *req, int32_t status,
+        CryptoDevBackendAsymOpInfo *asym_op_info)
+{
+    size_t s, len;
+
+    if (status != VIRTIO_CRYPTO_OK) {
+        return;
+    }
+
+    len = asym_op_info->dst_len;
+    if (!len) {
+        return;
+    }
+
+    s = iov_from_buf(req->in_iov, req->in_num, 0, asym_op_info->dst, len);
+    if (s != len) {
+        virtio_error(vdev, "virtio-crypto asym dest data incorrect");
+        return;
+    }
+
+    iov_discard_front(&req->in_iov, &req->in_num, len);
+
+    /* For akcipher, dst_len may be changed after operation */
+    req->in_len = sizeof(struct virtio_crypto_inhdr) + asym_op_info->dst_len;
+}
+
+
 static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)
 {
     VirtIOCrypto *vcrypto = req->vcrypto;
@@ -404,7 +522,10 @@ static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)
 
     if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
         virtio_crypto_sym_input_data_helper(vdev, req, status,
-                                            req->u.sym_op_info);
+                                            req->op_info.u.sym_op_info);
+    } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+        virtio_crypto_akcipher_input_data_helper(vdev, req, status,
+                                             req->op_info.u.asym_op_info);
     }
     stb_p(&req->in->status, status);
     virtqueue_push(req->vq, &req->elem, req->in_len);
@@ -543,41 +664,100 @@ err:
 static int
 virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto,
                struct virtio_crypto_sym_data_req *req,
-               CryptoDevBackendSymOpInfo **sym_op_info,
+               CryptoDevBackendOpInfo *op_info,
                struct iovec *iov, unsigned int out_num)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendSymOpInfo *sym_op_info;
     uint32_t op_type;
-    CryptoDevBackendSymOpInfo *op_info;
 
     op_type = ldl_le_p(&req->op_type);
-
     if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
-        op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
+        sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
                                               NULL, iov, out_num);
-        if (!op_info) {
+        if (!sym_op_info) {
             return -EFAULT;
         }
-        op_info->op_type = op_type;
     } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
-        op_info = virtio_crypto_sym_op_helper(vdev, NULL,
+        sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL,
                                               &req->u.chain.para,
                                               iov, out_num);
-        if (!op_info) {
+        if (!sym_op_info) {
             return -EFAULT;
         }
-        op_info->op_type = op_type;
     } else {
         /* VIRTIO_CRYPTO_SYM_OP_NONE */
         error_report("virtio-crypto unsupported cipher type");
         return -VIRTIO_CRYPTO_NOTSUPP;
     }
 
-    *sym_op_info = op_info;
+    sym_op_info->op_type = op_type;
+    op_info->u.sym_op_info = sym_op_info;
 
     return 0;
 }
 
+static int
+virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto,
+               struct virtio_crypto_akcipher_data_req *req,
+               CryptoDevBackendOpInfo *op_info,
+               struct iovec *iov, unsigned int out_num)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+    CryptoDevBackendAsymOpInfo *asym_op_info;
+    uint32_t src_len;
+    uint32_t dst_len;
+    uint32_t len;
+    uint8_t *src = NULL;
+    uint8_t *dst = NULL;
+
+    asym_op_info = g_malloc0(sizeof(CryptoDevBackendAsymOpInfo));
+    src_len = ldl_le_p(&req->para.src_data_len);
+    dst_len = ldl_le_p(&req->para.dst_data_len);
+
+    if (src_len > 0) {
+        src = g_malloc0(src_len);
+        len = iov_to_buf(iov, out_num, 0, src, src_len);
+        if (unlikely(len != src_len)) {
+            virtio_error(vdev, "virtio-crypto asym src data incorrect"
+                         "expected %u, actual %u", src_len, len);
+            goto err;
+        }
+
+        iov_discard_front(&iov, &out_num, src_len);
+    }
+
+    if (dst_len > 0) {
+        dst = g_malloc0(dst_len);
+
+        if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+            len = iov_to_buf(iov, out_num, 0, dst, dst_len);
+            if (unlikely(len != dst_len)) {
+                virtio_error(vdev, "virtio-crypto asym dst data incorrect"
+                             "expected %u, actual %u", dst_len, len);
+                goto err;
+            }
+
+            iov_discard_front(&iov, &out_num, dst_len);
+        }
+    }
+
+    asym_op_info->src_len = src_len;
+    asym_op_info->dst_len = dst_len;
+    asym_op_info->src = src;
+    asym_op_info->dst = dst;
+    op_info->u.asym_op_info = asym_op_info;
+
+    return 0;
+
+ err:
+    g_free(asym_op_info);
+    g_free(src);
+    g_free(dst);
+
+    return -EFAULT;
+}
+
 static int
 virtio_crypto_handle_request(VirtIOCryptoReq *request)
 {
@@ -595,8 +775,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
     unsigned out_num;
     uint32_t opcode;
     uint8_t status = VIRTIO_CRYPTO_ERR;
-    uint64_t session_id;
-    CryptoDevBackendSymOpInfo *sym_op_info = NULL;
+    CryptoDevBackendOpInfo *op_info = &request->op_info;
     Error *local_err = NULL;
 
     if (elem->out_num < 1 || elem->in_num < 1) {
@@ -639,15 +818,28 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
     request->in_iov = in_iov;
 
     opcode = ldl_le_p(&req.header.opcode);
-    session_id = ldq_le_p(&req.header.session_id);
+    op_info->session_id = ldq_le_p(&req.header.session_id);
+    op_info->op_code = opcode;
 
     switch (opcode) {
     case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
     case VIRTIO_CRYPTO_CIPHER_DECRYPT:
+        op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_SYM;
         ret = virtio_crypto_handle_sym_req(vcrypto,
-                         &req.u.sym_req,
-                         &sym_op_info,
+                         &req.u.sym_req, op_info,
+                         out_iov, out_num);
+        goto check_result;
+
+    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+        op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_ASYM;
+        ret = virtio_crypto_handle_asym_req(vcrypto,
+                         &req.u.akcipher_req, op_info,
                          out_iov, out_num);
+
+check_result:
         /* Serious errors, need to reset virtio crypto device */
         if (ret == -EFAULT) {
             return -1;
@@ -655,11 +847,8 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
             virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP);
             virtio_crypto_free_request(request);
         } else {
-            sym_op_info->session_id = session_id;
 
             /* Set request's parameter */
-            request->flags = CRYPTODEV_BACKEND_ALG_SYM;
-            request->u.sym_op_info = sym_op_info;
             ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev,
                                     request, queue_index, &local_err);
             if (ret < 0) {
@@ -674,6 +863,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
             virtio_crypto_free_request(request);
         }
         break;
+
     case VIRTIO_CRYPTO_HASH:
     case VIRTIO_CRYPTO_MAC:
     case VIRTIO_CRYPTO_AEAD_ENCRYPT:
@@ -779,6 +969,7 @@ static void virtio_crypto_init_config(VirtIODevice *vdev)
     vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l;
     vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h;
     vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo;
+    vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo;
     vcrypto->conf.max_cipher_key_len =
                   vcrypto->conf.cryptodev->conf.max_cipher_key_len;
     vcrypto->conf.max_auth_key_len =
@@ -891,6 +1082,7 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config)
     stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len);
     stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len);
     stq_le_p(&crypto_cfg.max_size, c->conf.max_size);
+    stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo);
 
     memcpy(config, &crypto_cfg, c->config_size);
 }
diff --git a/include/hw/virtio/virtio-crypto.h b/include/hw/virtio/virtio-crypto.h
index a2228d7b2e..348749f5d5 100644
--- a/include/hw/virtio/virtio-crypto.h
+++ b/include/hw/virtio/virtio-crypto.h
@@ -50,6 +50,7 @@ typedef struct VirtIOCryptoConf {
     uint32_t mac_algo_l;
     uint32_t mac_algo_h;
     uint32_t aead_algo;
+    uint32_t akcipher_algo;
 
     /* Maximum length of cipher key */
     uint32_t max_cipher_key_len;
@@ -71,9 +72,7 @@ typedef struct VirtIOCryptoReq {
     size_t in_len;
     VirtQueue *vq;
     struct VirtIOCrypto *vcrypto;
-    union {
-        CryptoDevBackendSymOpInfo *sym_op_info;
-    } u;
+    CryptoDevBackendOpInfo op_info;
 } VirtIOCryptoReq;
 
 typedef struct VirtIOCryptoQueue {
diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h
index f4d4057d4d..b306775849 100644
--- a/include/sysemu/cryptodev.h
+++ b/include/sysemu/cryptodev.h
@@ -50,13 +50,13 @@ typedef struct CryptoDevBackendClient
 
 enum CryptoDevBackendAlgType {
     CRYPTODEV_BACKEND_ALG_SYM,
+    CRYPTODEV_BACKEND_ALG_ASYM,
     CRYPTODEV_BACKEND_ALG__MAX,
 };
 
 /**
  * CryptoDevBackendSymSessionInfo:
  *
- * @op_code: operation code (refer to virtio_crypto.h)
  * @cipher_alg: algorithm type of CIPHER
  * @key_len: byte length of cipher key
  * @hash_alg: algorithm type of HASH/MAC
@@ -74,7 +74,6 @@ enum CryptoDevBackendAlgType {
  */
 typedef struct CryptoDevBackendSymSessionInfo {
     /* corresponding with virtio crypto spec */
-    uint32_t op_code;
     uint32_t cipher_alg;
     uint32_t key_len;
     uint32_t hash_alg;
@@ -89,11 +88,41 @@ typedef struct CryptoDevBackendSymSessionInfo {
     uint8_t *auth_key;
 } CryptoDevBackendSymSessionInfo;
 
+/**
+ * CryptoDevBackendAsymSessionInfo:
+ */
+typedef struct CryptoDevBackendRsaPara {
+    uint32_t padding_algo;
+    uint32_t hash_algo;
+} CryptoDevBackendRsaPara;
+
+typedef struct CryptoDevBackendEcdsaPara {
+    uint32_t curve_id;
+} CryptoDevBackendEcdsaPara;
+
+typedef struct CryptoDevBackendAsymSessionInfo {
+    /* corresponding with virtio crypto spec */
+    uint32_t algo;
+    uint32_t keytype;
+    uint32_t keylen;
+    uint8_t *key;
+    union {
+        CryptoDevBackendRsaPara rsa;
+        CryptoDevBackendEcdsaPara ecdsa;
+    } u;
+} CryptoDevBackendAsymSessionInfo;
+
+typedef struct CryptoDevBackendSessionInfo {
+    uint32_t op_code;
+    union {
+        CryptoDevBackendSymSessionInfo sym_sess_info;
+        CryptoDevBackendAsymSessionInfo asym_sess_info;
+    } u;
+} CryptoDevBackendSessionInfo;
+
 /**
  * CryptoDevBackendSymOpInfo:
  *
- * @session_id: session index which was previously
- *              created by cryptodev_backend_sym_create_session()
  * @aad_len: byte length of additional authenticated data
  * @iv_len: byte length of initialization vector or counter
  * @src_len: byte length of source data
@@ -119,7 +148,6 @@ typedef struct CryptoDevBackendSymSessionInfo {
  *
  */
 typedef struct CryptoDevBackendSymOpInfo {
-    uint64_t session_id;
     uint32_t aad_len;
     uint32_t iv_len;
     uint32_t src_len;
@@ -138,6 +166,33 @@ typedef struct CryptoDevBackendSymOpInfo {
     uint8_t data[];
 } CryptoDevBackendSymOpInfo;
 
+
+/**
+ * CryptoDevBackendAsymOpInfo:
+ *
+ * @src_len: byte length of source data
+ * @dst_len: byte length of destination data
+ * @src: point to the source data
+ * @dst: point to the destination data
+ *
+ */
+typedef struct CryptoDevBackendAsymOpInfo {
+    uint32_t src_len;
+    uint32_t dst_len;
+    uint8_t *src;
+    uint8_t *dst;
+} CryptoDevBackendAsymOpInfo;
+
+typedef struct CryptoDevBackendOpInfo {
+    enum CryptoDevBackendAlgType algtype;
+    uint32_t op_code;
+    uint64_t session_id;
+    union {
+        CryptoDevBackendSymOpInfo *sym_op_info;
+        CryptoDevBackendAsymOpInfo *asym_op_info;
+    } u;
+} CryptoDevBackendOpInfo;
+
 struct CryptoDevBackendClass {
     ObjectClass parent_class;
 
@@ -145,13 +200,13 @@ struct CryptoDevBackendClass {
     void (*cleanup)(CryptoDevBackend *backend, Error **errp);
 
     int64_t (*create_session)(CryptoDevBackend *backend,
-                       CryptoDevBackendSymSessionInfo *sess_info,
+                       CryptoDevBackendSessionInfo *sess_info,
                        uint32_t queue_index, Error **errp);
     int (*close_session)(CryptoDevBackend *backend,
                            uint64_t session_id,
                            uint32_t queue_index, Error **errp);
-    int (*do_sym_op)(CryptoDevBackend *backend,
-                     CryptoDevBackendSymOpInfo *op_info,
+    int (*do_op)(CryptoDevBackend *backend,
+                     CryptoDevBackendOpInfo *op_info,
                      uint32_t queue_index, Error **errp);
 };
 
@@ -190,6 +245,7 @@ struct CryptoDevBackendConf {
     uint32_t mac_algo_l;
     uint32_t mac_algo_h;
     uint32_t aead_algo;
+    uint32_t akcipher_algo;
     /* Maximum length of cipher key */
     uint32_t max_cipher_key_len;
     /* Maximum length of authenticated key */
@@ -247,34 +303,34 @@ void cryptodev_backend_cleanup(
            Error **errp);
 
 /**
- * cryptodev_backend_sym_create_session:
+ * cryptodev_backend_create_session:
  * @backend: the cryptodev backend object
  * @sess_info: parameters needed by session creating
  * @queue_index: queue index of cryptodev backend client
  * @errp: pointer to a NULL-initialized error object
  *
- * Create a session for symmetric algorithms
+ * Create a session for symmetric/symmetric algorithms
  *
  * Returns: session id on success, or -1 on error
  */
-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
            CryptoDevBackend *backend,
-           CryptoDevBackendSymSessionInfo *sess_info,
+           CryptoDevBackendSessionInfo *sess_info,
            uint32_t queue_index, Error **errp);
 
 /**
- * cryptodev_backend_sym_close_session:
+ * cryptodev_backend_close_session:
  * @backend: the cryptodev backend object
  * @session_id: the session id
  * @queue_index: queue index of cryptodev backend client
  * @errp: pointer to a NULL-initialized error object
  *
- * Close a session for symmetric algorithms which was previously
- * created by cryptodev_backend_sym_create_session()
+ * Close a session for which was previously
+ * created by cryptodev_backend_create_session()
  *
  * Returns: 0 on success, or Negative on error
  */
-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
            CryptoDevBackend *backend,
            uint64_t session_id,
            uint32_t queue_index, Error **errp);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
  2022-03-23  2:49 ` zhenwei pi
@ 2022-03-23  5:17   ` Eric Biggers
  -1 siblings, 0 replies; 62+ messages in thread
From: Eric Biggers @ 2022-03-23  5:17 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, jasowang, virtualization, qemu-devel,
	linux-crypto, herbert

On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> 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 (3):
>   crypto-akcipher: Introduce akcipher types to qapi
>   crypto: Implement RSA algorithm by hogweed
>   tests/crypto: Add test suite for crypto akcipher
> 
> Zhenwei Pi (3):
>   virtio-crypto: header update
>   crypto: Introduce akcipher crypto class
>   virtio-crypto: Introduce RSA algorithm

You forgot to describe the point of this patchset and what its use case is.
Like any other Linux kernel patchset, that needs to be in the cover letter.

- Eric

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23  5:17   ` Eric Biggers
  0 siblings, 0 replies; 62+ messages in thread
From: Eric Biggers @ 2022-03-23  5:17 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto

On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> 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 (3):
>   crypto-akcipher: Introduce akcipher types to qapi
>   crypto: Implement RSA algorithm by hogweed
>   tests/crypto: Add test suite for crypto akcipher
> 
> Zhenwei Pi (3):
>   virtio-crypto: header update
>   crypto: Introduce akcipher crypto class
>   virtio-crypto: Introduce RSA algorithm

You forgot to describe the point of this patchset and what its use case is.
Like any other Linux kernel patchset, that needs to be in the cover letter.

- Eric


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
  2022-03-23  5:17   ` Eric Biggers
  (?)
@ 2022-03-23  7:32     ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  7:32 UTC (permalink / raw)
  To: Eric Biggers
  Cc: arei.gonglei, mst, jasowang, virtualization, qemu-devel,
	linux-crypto, herbert, helei.sig11


On 3/23/22 13:17, Eric Biggers wrote:
> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>> 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 (3):
>>    crypto-akcipher: Introduce akcipher types to qapi
>>    crypto: Implement RSA algorithm by hogweed
>>    tests/crypto: Add test suite for crypto akcipher
>>
>> Zhenwei Pi (3):
>>    virtio-crypto: header update
>>    crypto: Introduce akcipher crypto class
>>    virtio-crypto: Introduce RSA algorithm
> 
> You forgot to describe the point of this patchset and what its use case is.
> Like any other Linux kernel patchset, that needs to be in the cover letter.
> 
> - Eric
Thanks Eric for pointing this missing part.

This feature provides akcipher service offloading capability. QEMU side 
handles asymmetric requests via virtio-crypto devices from guest side, 
do encrypt/decrypt/sign/verify operations on host side, and return the 
result to guest.

This patchset implements a RSA backend by hogweed from nettle, it works 
together with guest patch:
https://lkml.org/lkml/2022/3/1/1425

-- 
zhenwei pi

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23  7:32     ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  7:32 UTC (permalink / raw)
  To: Eric Biggers
  Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, helei.sig11


On 3/23/22 13:17, Eric Biggers wrote:
> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>> 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 (3):
>>    crypto-akcipher: Introduce akcipher types to qapi
>>    crypto: Implement RSA algorithm by hogweed
>>    tests/crypto: Add test suite for crypto akcipher
>>
>> Zhenwei Pi (3):
>>    virtio-crypto: header update
>>    crypto: Introduce akcipher crypto class
>>    virtio-crypto: Introduce RSA algorithm
> 
> You forgot to describe the point of this patchset and what its use case is.
> Like any other Linux kernel patchset, that needs to be in the cover letter.
> 
> - Eric
Thanks Eric for pointing this missing part.

This feature provides akcipher service offloading capability. QEMU side 
handles asymmetric requests via virtio-crypto devices from guest side, 
do encrypt/decrypt/sign/verify operations on host side, and return the 
result to guest.

This patchset implements a RSA backend by hogweed from nettle, it works 
together with guest patch:
https://lkml.org/lkml/2022/3/1/1425

-- 
zhenwei pi
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23  7:32     ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23  7:32 UTC (permalink / raw)
  To: Eric Biggers
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, helei.sig11


On 3/23/22 13:17, Eric Biggers wrote:
> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>> 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 (3):
>>    crypto-akcipher: Introduce akcipher types to qapi
>>    crypto: Implement RSA algorithm by hogweed
>>    tests/crypto: Add test suite for crypto akcipher
>>
>> Zhenwei Pi (3):
>>    virtio-crypto: header update
>>    crypto: Introduce akcipher crypto class
>>    virtio-crypto: Introduce RSA algorithm
> 
> You forgot to describe the point of this patchset and what its use case is.
> Like any other Linux kernel patchset, that needs to be in the cover letter.
> 
> - Eric
Thanks Eric for pointing this missing part.

This feature provides akcipher service offloading capability. QEMU side 
handles asymmetric requests via virtio-crypto devices from guest side, 
do encrypt/decrypt/sign/verify operations on host side, and return the 
result to guest.

This patchset implements a RSA backend by hogweed from nettle, it works 
together with guest patch:
https://lkml.org/lkml/2022/3/1/1425

-- 
zhenwei pi


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
  2022-03-23  2:49 ` zhenwei pi
@ 2022-03-23 12:36   ` Philippe Mathieu-Daudé
  -1 siblings, 0 replies; 62+ messages in thread
From: Philippe Mathieu-Daudé @ 2022-03-23 12:36 UTC (permalink / raw)
  To: zhenwei pi, arei.gonglei, mst, Laurent Vivier, Daniel P. Berrangé
  Cc: herbert, jasowang, qemu-devel, virtualization, linux-crypto

Cc'ing Daniel & Laurent.

On 23/3/22 03:49, zhenwei pi wrote:
> 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 (3):
>    crypto-akcipher: Introduce akcipher types to qapi
>    crypto: Implement RSA algorithm by hogweed
>    tests/crypto: Add test suite for crypto akcipher
> 
> Zhenwei Pi (3):
>    virtio-crypto: header update
>    crypto: Introduce akcipher crypto class
>    virtio-crypto: Introduce RSA algorithm
> 
>   backends/cryptodev-builtin.c                  | 319 +++++++-
>   backends/cryptodev-vhost-user.c               |  34 +-
>   backends/cryptodev.c                          |  32 +-
>   crypto/akcipher-nettle.c                      | 523 +++++++++++++
>   crypto/akcipher.c                             |  81 ++
>   crypto/asn1_decoder.c                         | 185 +++++
>   crypto/asn1_decoder.h                         |  42 +
>   crypto/meson.build                            |   4 +
>   hw/virtio/virtio-crypto.c                     | 326 ++++++--
>   include/crypto/akcipher.h                     | 155 ++++
>   include/hw/virtio/virtio-crypto.h             |   5 +-
>   .../standard-headers/linux/virtio_crypto.h    |  82 +-
>   include/sysemu/cryptodev.h                    |  88 ++-
>   meson.build                                   |  11 +
>   qapi/crypto.json                              |  86 +++
>   tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
>   tests/bench/meson.build                       |   6 +
>   tests/bench/test_akcipher_keys.inc            | 277 +++++++
>   tests/unit/meson.build                        |   1 +
>   tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
>   20 files changed, 2990 insertions(+), 145 deletions(-)
>   create mode 100644 crypto/akcipher-nettle.c
>   create mode 100644 crypto/akcipher.c
>   create mode 100644 crypto/asn1_decoder.c
>   create mode 100644 crypto/asn1_decoder.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
> 


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23 12:36   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 62+ messages in thread
From: Philippe Mathieu-Daudé @ 2022-03-23 12:36 UTC (permalink / raw)
  To: zhenwei pi, arei.gonglei, mst, Laurent Vivier, Daniel P. Berrangé
  Cc: linux-crypto, jasowang, virtualization, herbert, qemu-devel

Cc'ing Daniel & Laurent.

On 23/3/22 03:49, zhenwei pi wrote:
> 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 (3):
>    crypto-akcipher: Introduce akcipher types to qapi
>    crypto: Implement RSA algorithm by hogweed
>    tests/crypto: Add test suite for crypto akcipher
> 
> Zhenwei Pi (3):
>    virtio-crypto: header update
>    crypto: Introduce akcipher crypto class
>    virtio-crypto: Introduce RSA algorithm
> 
>   backends/cryptodev-builtin.c                  | 319 +++++++-
>   backends/cryptodev-vhost-user.c               |  34 +-
>   backends/cryptodev.c                          |  32 +-
>   crypto/akcipher-nettle.c                      | 523 +++++++++++++
>   crypto/akcipher.c                             |  81 ++
>   crypto/asn1_decoder.c                         | 185 +++++
>   crypto/asn1_decoder.h                         |  42 +
>   crypto/meson.build                            |   4 +
>   hw/virtio/virtio-crypto.c                     | 326 ++++++--
>   include/crypto/akcipher.h                     | 155 ++++
>   include/hw/virtio/virtio-crypto.h             |   5 +-
>   .../standard-headers/linux/virtio_crypto.h    |  82 +-
>   include/sysemu/cryptodev.h                    |  88 ++-
>   meson.build                                   |  11 +
>   qapi/crypto.json                              |  86 +++
>   tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
>   tests/bench/meson.build                       |   6 +
>   tests/bench/test_akcipher_keys.inc            | 277 +++++++
>   tests/unit/meson.build                        |   1 +
>   tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
>   20 files changed, 2990 insertions(+), 145 deletions(-)
>   create mode 100644 crypto/akcipher-nettle.c
>   create mode 100644 crypto/akcipher.c
>   create mode 100644 crypto/asn1_decoder.c
>   create mode 100644 crypto/asn1_decoder.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
> 



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
  2022-03-23  2:49 ` zhenwei pi
  (?)
@ 2022-03-23 12:36   ` Michael S. Tsirkin
  -1 siblings, 0 replies; 62+ messages in thread
From: Michael S. Tsirkin @ 2022-03-23 12:36 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, jasowang, virtualization, qemu-devel, linux-crypto,
	herbert

On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> 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

Thanks!
I tagged this but qemu is in freeze. If possible pls ping or
repost after the release to help make sure I don't lose it.

> 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 (3):
>   crypto-akcipher: Introduce akcipher types to qapi
>   crypto: Implement RSA algorithm by hogweed
>   tests/crypto: Add test suite for crypto akcipher
> 
> Zhenwei Pi (3):
>   virtio-crypto: header update
>   crypto: Introduce akcipher crypto class
>   virtio-crypto: Introduce RSA algorithm
> 
>  backends/cryptodev-builtin.c                  | 319 +++++++-
>  backends/cryptodev-vhost-user.c               |  34 +-
>  backends/cryptodev.c                          |  32 +-
>  crypto/akcipher-nettle.c                      | 523 +++++++++++++
>  crypto/akcipher.c                             |  81 ++
>  crypto/asn1_decoder.c                         | 185 +++++
>  crypto/asn1_decoder.h                         |  42 +
>  crypto/meson.build                            |   4 +
>  hw/virtio/virtio-crypto.c                     | 326 ++++++--
>  include/crypto/akcipher.h                     | 155 ++++
>  include/hw/virtio/virtio-crypto.h             |   5 +-
>  .../standard-headers/linux/virtio_crypto.h    |  82 +-
>  include/sysemu/cryptodev.h                    |  88 ++-
>  meson.build                                   |  11 +
>  qapi/crypto.json                              |  86 +++
>  tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
>  tests/bench/meson.build                       |   6 +
>  tests/bench/test_akcipher_keys.inc            | 277 +++++++
>  tests/unit/meson.build                        |   1 +
>  tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
>  20 files changed, 2990 insertions(+), 145 deletions(-)
>  create mode 100644 crypto/akcipher-nettle.c
>  create mode 100644 crypto/akcipher.c
>  create mode 100644 crypto/asn1_decoder.c
>  create mode 100644 crypto/asn1_decoder.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
> 
> -- 
> 2.25.1


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23 12:36   ` Michael S. Tsirkin
  0 siblings, 0 replies; 62+ messages in thread
From: Michael S. Tsirkin @ 2022-03-23 12:36 UTC (permalink / raw)
  To: zhenwei pi; +Cc: herbert, qemu-devel, virtualization, linux-crypto

On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> 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

Thanks!
I tagged this but qemu is in freeze. If possible pls ping or
repost after the release to help make sure I don't lose it.

> 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 (3):
>   crypto-akcipher: Introduce akcipher types to qapi
>   crypto: Implement RSA algorithm by hogweed
>   tests/crypto: Add test suite for crypto akcipher
> 
> Zhenwei Pi (3):
>   virtio-crypto: header update
>   crypto: Introduce akcipher crypto class
>   virtio-crypto: Introduce RSA algorithm
> 
>  backends/cryptodev-builtin.c                  | 319 +++++++-
>  backends/cryptodev-vhost-user.c               |  34 +-
>  backends/cryptodev.c                          |  32 +-
>  crypto/akcipher-nettle.c                      | 523 +++++++++++++
>  crypto/akcipher.c                             |  81 ++
>  crypto/asn1_decoder.c                         | 185 +++++
>  crypto/asn1_decoder.h                         |  42 +
>  crypto/meson.build                            |   4 +
>  hw/virtio/virtio-crypto.c                     | 326 ++++++--
>  include/crypto/akcipher.h                     | 155 ++++
>  include/hw/virtio/virtio-crypto.h             |   5 +-
>  .../standard-headers/linux/virtio_crypto.h    |  82 +-
>  include/sysemu/cryptodev.h                    |  88 ++-
>  meson.build                                   |  11 +
>  qapi/crypto.json                              |  86 +++
>  tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
>  tests/bench/meson.build                       |   6 +
>  tests/bench/test_akcipher_keys.inc            | 277 +++++++
>  tests/unit/meson.build                        |   1 +
>  tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
>  20 files changed, 2990 insertions(+), 145 deletions(-)
>  create mode 100644 crypto/akcipher-nettle.c
>  create mode 100644 crypto/akcipher.c
>  create mode 100644 crypto/asn1_decoder.c
>  create mode 100644 crypto/asn1_decoder.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
> 
> -- 
> 2.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23 12:36   ` Michael S. Tsirkin
  0 siblings, 0 replies; 62+ messages in thread
From: Michael S. Tsirkin @ 2022-03-23 12:36 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto

On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> 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

Thanks!
I tagged this but qemu is in freeze. If possible pls ping or
repost after the release to help make sure I don't lose it.

> 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 (3):
>   crypto-akcipher: Introduce akcipher types to qapi
>   crypto: Implement RSA algorithm by hogweed
>   tests/crypto: Add test suite for crypto akcipher
> 
> Zhenwei Pi (3):
>   virtio-crypto: header update
>   crypto: Introduce akcipher crypto class
>   virtio-crypto: Introduce RSA algorithm
> 
>  backends/cryptodev-builtin.c                  | 319 +++++++-
>  backends/cryptodev-vhost-user.c               |  34 +-
>  backends/cryptodev.c                          |  32 +-
>  crypto/akcipher-nettle.c                      | 523 +++++++++++++
>  crypto/akcipher.c                             |  81 ++
>  crypto/asn1_decoder.c                         | 185 +++++
>  crypto/asn1_decoder.h                         |  42 +
>  crypto/meson.build                            |   4 +
>  hw/virtio/virtio-crypto.c                     | 326 ++++++--
>  include/crypto/akcipher.h                     | 155 ++++
>  include/hw/virtio/virtio-crypto.h             |   5 +-
>  .../standard-headers/linux/virtio_crypto.h    |  82 +-
>  include/sysemu/cryptodev.h                    |  88 ++-
>  meson.build                                   |  11 +
>  qapi/crypto.json                              |  86 +++
>  tests/bench/benchmark-crypto-akcipher.c       | 163 ++++
>  tests/bench/meson.build                       |   6 +
>  tests/bench/test_akcipher_keys.inc            | 277 +++++++
>  tests/unit/meson.build                        |   1 +
>  tests/unit/test-crypto-akcipher.c             | 715 ++++++++++++++++++
>  20 files changed, 2990 insertions(+), 145 deletions(-)
>  create mode 100644 crypto/akcipher-nettle.c
>  create mode 100644 crypto/akcipher.c
>  create mode 100644 crypto/asn1_decoder.c
>  create mode 100644 crypto/asn1_decoder.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
> 
> -- 
> 2.25.1



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
  2022-03-23  2:49   ` zhenwei pi
  (?)
@ 2022-03-23 13:08     ` Daniel P. Berrangé
  -1 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:08 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, herbert, jasowang, qemu-devel, virtualization,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:08AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce akcipher types, also include RSA & ECDSA related types.
> 
> Signed-off-by: Lei He <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 1ec54c15ca..d44c38e3b1 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -540,3 +540,89 @@
>    'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
>              '*sanity-check': 'bool',
>              '*passwordid': 'str' } }
> +##
> +# @QCryptoAkcipherAlgorithm:

Should be named  QCryptoAkCipherAlgorithm

> +#
> +# The supported algorithms for asymmetric encryption ciphers
> +#
> +# @rsa: RSA algorithm
> +# @ecdsa: ECDSA algorithm
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherAlgorithm',
> +  'prefix': 'QCRYPTO_AKCIPHER_ALG',
> +  'data': ['rsa', 'ecdsa']}
> +
> +##
> +# @QCryptoAkcipherKeyType:

Should be named  QCryptoAkCipherKeyType

> +#
> +# The type of asymmetric keys.
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherKeyType',
> +  'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
> +  'data': ['public', 'private']}
> +
> +##
> +# @QCryptoRsaHashAlgorithm:
> +#
> +# The hash algorithm for RSA pkcs1 padding algothrim
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoRsaHashAlgorithm',
> +  'prefix': 'QCRYPTO_RSA_HASH_ALG',
> +  'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]}

We already have QCryptoHashAlgorithm and I don't see the
benefit in duplicating it here.

We don't have md2, md3, and md4 in QCryptoHashAlgorithm, but
that doesn't look like a real negative as I can't imagine
those should be used today.

> +##
> +# @QCryptoRsaPaddingAlgorithm:
> +#
> +# The padding algorithm for RSA.
> +#
> +# @raw: no padding used
> +# @pkcs1: pkcs1#v1.5
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoRsaPaddingAlgorithm',
> +  'prefix': 'QCRYPTO_RSA_PADDING_ALG',
> +  'data': ['raw', 'pkcs1']}
> +
> +##
> +# @QCryptoCurveId:

Should be named  QCryptoCurveID

> +#
> +# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoCurveId',
> +  'prefix': 'QCRYPTO_CURVE_ID',
> +  'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']}


> +
> +##
> +# @QCryptoRsaOptions:

This should be named  QCryptoAkCipherOptionsRSA

> +#
> +# Specific parameters for RSA algorithm.
> +#
> +# @hash-algo: QCryptoRsaHashAlgorithm
> +# @padding-algo: QCryptoRsaPaddingAlgorithm
> +#
> +# Since: 7.0
> +##
> +{ 'struct': 'QCryptoRsaOptions',
> +  'data': { 'hash-algo':'QCryptoRsaHashAlgorithm',
> +            'padding-algo': 'QCryptoRsaPaddingAlgorithm'}}

Our naming convention is  'XXX-alg' rather than 'XXX-algo'.

> +
> +##
> +# @QCryptoEcdsaOptions:

This should be named  QCryptoAkCipherOptionsECDSA

> +#
> +# Specific parameter for ECDSA algorithm.
> +#
> +# @curve-id: QCryptoCurveId
> +#
> +# Since: 7.0
> +##
> +{ 'struct': 'QCryptoEcdsaOptions',
> +  'data': { 'curve-id': 'QCryptoCurveId' }}

Having these two structs standalone looks wrong to me. I suspect that
callers will need to be able to conditionally pass in either one, and
so require the API to use a discriminated union

  { 'union': 'QCryptoAkCipherOptions'
    'base': { 'algorithm': 'QCryptoAkCipherAlgorithm' },
    'discriminator': 'algorithm',
    'data': { 'rsa': 'QCryptoAkCipherOptionsRSA' ,
              'ecdsa': 'QCryptoAkCipherOptionsECDSA' } }


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 :|


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
@ 2022-03-23 13:08     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:08 UTC (permalink / raw)
  To: zhenwei pi; +Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:08AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce akcipher types, also include RSA & ECDSA related types.
> 
> Signed-off-by: Lei He <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 1ec54c15ca..d44c38e3b1 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -540,3 +540,89 @@
>    'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
>              '*sanity-check': 'bool',
>              '*passwordid': 'str' } }
> +##
> +# @QCryptoAkcipherAlgorithm:

Should be named  QCryptoAkCipherAlgorithm

> +#
> +# The supported algorithms for asymmetric encryption ciphers
> +#
> +# @rsa: RSA algorithm
> +# @ecdsa: ECDSA algorithm
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherAlgorithm',
> +  'prefix': 'QCRYPTO_AKCIPHER_ALG',
> +  'data': ['rsa', 'ecdsa']}
> +
> +##
> +# @QCryptoAkcipherKeyType:

Should be named  QCryptoAkCipherKeyType

> +#
> +# The type of asymmetric keys.
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherKeyType',
> +  'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
> +  'data': ['public', 'private']}
> +
> +##
> +# @QCryptoRsaHashAlgorithm:
> +#
> +# The hash algorithm for RSA pkcs1 padding algothrim
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoRsaHashAlgorithm',
> +  'prefix': 'QCRYPTO_RSA_HASH_ALG',
> +  'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]}

We already have QCryptoHashAlgorithm and I don't see the
benefit in duplicating it here.

We don't have md2, md3, and md4 in QCryptoHashAlgorithm, but
that doesn't look like a real negative as I can't imagine
those should be used today.

> +##
> +# @QCryptoRsaPaddingAlgorithm:
> +#
> +# The padding algorithm for RSA.
> +#
> +# @raw: no padding used
> +# @pkcs1: pkcs1#v1.5
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoRsaPaddingAlgorithm',
> +  'prefix': 'QCRYPTO_RSA_PADDING_ALG',
> +  'data': ['raw', 'pkcs1']}
> +
> +##
> +# @QCryptoCurveId:

Should be named  QCryptoCurveID

> +#
> +# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoCurveId',
> +  'prefix': 'QCRYPTO_CURVE_ID',
> +  'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']}


> +
> +##
> +# @QCryptoRsaOptions:

This should be named  QCryptoAkCipherOptionsRSA

> +#
> +# Specific parameters for RSA algorithm.
> +#
> +# @hash-algo: QCryptoRsaHashAlgorithm
> +# @padding-algo: QCryptoRsaPaddingAlgorithm
> +#
> +# Since: 7.0
> +##
> +{ 'struct': 'QCryptoRsaOptions',
> +  'data': { 'hash-algo':'QCryptoRsaHashAlgorithm',
> +            'padding-algo': 'QCryptoRsaPaddingAlgorithm'}}

Our naming convention is  'XXX-alg' rather than 'XXX-algo'.

> +
> +##
> +# @QCryptoEcdsaOptions:

This should be named  QCryptoAkCipherOptionsECDSA

> +#
> +# Specific parameter for ECDSA algorithm.
> +#
> +# @curve-id: QCryptoCurveId
> +#
> +# Since: 7.0
> +##
> +{ 'struct': 'QCryptoEcdsaOptions',
> +  'data': { 'curve-id': 'QCryptoCurveId' }}

Having these two structs standalone looks wrong to me. I suspect that
callers will need to be able to conditionally pass in either one, and
so require the API to use a discriminated union

  { 'union': 'QCryptoAkCipherOptions'
    'base': { 'algorithm': 'QCryptoAkCipherAlgorithm' },
    'discriminator': 'algorithm',
    'data': { 'rsa': 'QCryptoAkCipherOptionsRSA' ,
              'ecdsa': 'QCryptoAkCipherOptionsECDSA' } }


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 :|

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
@ 2022-03-23 13:08     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:08 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:08AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce akcipher types, also include RSA & ECDSA related types.
> 
> Signed-off-by: Lei He <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 1ec54c15ca..d44c38e3b1 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -540,3 +540,89 @@
>    'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
>              '*sanity-check': 'bool',
>              '*passwordid': 'str' } }
> +##
> +# @QCryptoAkcipherAlgorithm:

Should be named  QCryptoAkCipherAlgorithm

> +#
> +# The supported algorithms for asymmetric encryption ciphers
> +#
> +# @rsa: RSA algorithm
> +# @ecdsa: ECDSA algorithm
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherAlgorithm',
> +  'prefix': 'QCRYPTO_AKCIPHER_ALG',
> +  'data': ['rsa', 'ecdsa']}
> +
> +##
> +# @QCryptoAkcipherKeyType:

Should be named  QCryptoAkCipherKeyType

> +#
> +# The type of asymmetric keys.
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherKeyType',
> +  'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
> +  'data': ['public', 'private']}
> +
> +##
> +# @QCryptoRsaHashAlgorithm:
> +#
> +# The hash algorithm for RSA pkcs1 padding algothrim
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoRsaHashAlgorithm',
> +  'prefix': 'QCRYPTO_RSA_HASH_ALG',
> +  'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]}

We already have QCryptoHashAlgorithm and I don't see the
benefit in duplicating it here.

We don't have md2, md3, and md4 in QCryptoHashAlgorithm, but
that doesn't look like a real negative as I can't imagine
those should be used today.

> +##
> +# @QCryptoRsaPaddingAlgorithm:
> +#
> +# The padding algorithm for RSA.
> +#
> +# @raw: no padding used
> +# @pkcs1: pkcs1#v1.5
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoRsaPaddingAlgorithm',
> +  'prefix': 'QCRYPTO_RSA_PADDING_ALG',
> +  'data': ['raw', 'pkcs1']}
> +
> +##
> +# @QCryptoCurveId:

Should be named  QCryptoCurveID

> +#
> +# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoCurveId',
> +  'prefix': 'QCRYPTO_CURVE_ID',
> +  'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']}


> +
> +##
> +# @QCryptoRsaOptions:

This should be named  QCryptoAkCipherOptionsRSA

> +#
> +# Specific parameters for RSA algorithm.
> +#
> +# @hash-algo: QCryptoRsaHashAlgorithm
> +# @padding-algo: QCryptoRsaPaddingAlgorithm
> +#
> +# Since: 7.0
> +##
> +{ 'struct': 'QCryptoRsaOptions',
> +  'data': { 'hash-algo':'QCryptoRsaHashAlgorithm',
> +            'padding-algo': 'QCryptoRsaPaddingAlgorithm'}}

Our naming convention is  'XXX-alg' rather than 'XXX-algo'.

> +
> +##
> +# @QCryptoEcdsaOptions:

This should be named  QCryptoAkCipherOptionsECDSA

> +#
> +# Specific parameter for ECDSA algorithm.
> +#
> +# @curve-id: QCryptoCurveId
> +#
> +# Since: 7.0
> +##
> +{ 'struct': 'QCryptoEcdsaOptions',
> +  'data': { 'curve-id': 'QCryptoCurveId' }}

Having these two structs standalone looks wrong to me. I suspect that
callers will need to be able to conditionally pass in either one, and
so require the API to use a discriminated union

  { 'union': 'QCryptoAkCipherOptions'
    'base': { 'algorithm': 'QCryptoAkCipherAlgorithm' },
    'discriminator': 'algorithm',
    'data': { 'rsa': 'QCryptoAkCipherOptionsRSA' ,
              'ecdsa': 'QCryptoAkCipherOptionsECDSA' } }


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 :|



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 3/6] crypto: Introduce akcipher crypto class
  2022-03-23  2:49   ` zhenwei pi
  (?)
@ 2022-03-23 13:33     ` Daniel P. Berrangé
  -1 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:33 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, herbert, jasowang, qemu-devel, virtualization,
	linux-crypto, lei he

On Wed, Mar 23, 2022 at 10:49:09AM +0800, zhenwei pi wrote:
> Support basic asymmetric operations: encrypt, decrypt, sign and
> verify.
> 
> Co-developed-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  crypto/akcipher.c         |  78 +++++++++++++++++++++
>  crypto/meson.build        |   1 +
>  include/crypto/akcipher.h | 139 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 218 insertions(+)
>  create mode 100644 crypto/akcipher.c
>  create mode 100644 include/crypto/akcipher.h
> 
> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
> new file mode 100644
> index 0000000000..1e52f2fd76
> --- /dev/null
> +++ b/crypto/akcipher.c
> @@ -0,0 +1,78 @@
> +/*
> + * QEMU Crypto akcipher algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: zhenwei pi <pizhenwei@bytedance.com>
> + *
> + * 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 "qemu/host-utils.h"
> +#include "qapi/error.h"
> +#include "crypto/akcipher.h"
> +
> +QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
> +                                      QCryptoAkcipherKeyType type,
> +                                      const uint8_t *key, size_t keylen,
> +                                      void *para, Error **errp)
> +{
> +    QCryptoAkcipher *akcipher = NULL;
> +
> +    return akcipher;
> +}
> +
> +int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
> +                             const void *data, size_t data_len,
> +                             void *enc, size_t enc_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->encrypt(akcipher, data, data_len, enc, enc_len, errp);
> +}
> +
> +int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
> +                             const void *enc, size_t enc_len,
> +                             void *data, size_t data_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->decrypt(akcipher, enc, enc_len, data, data_len, errp);
> +}
> +
> +int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
> +                          const void *data, size_t data_len,
> +                          void *sig, size_t sig_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->sign(akcipher, data, data_len, sig, sig_len, errp);
> +}
> +
> +int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
> +                            const void *sig, size_t sig_len,
> +                            const void *data, size_t data_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->verify(akcipher, sig, sig_len, data, data_len, errp);
> +}
> +
> +int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->free(akcipher, errp);
> +}
> diff --git a/crypto/meson.build b/crypto/meson.build
> index 19c44bea89..c32b57aeda 100644
> --- a/crypto/meson.build
> +++ b/crypto/meson.build
> @@ -19,6 +19,7 @@ crypto_ss.add(files(
>    'tlscredspsk.c',
>    'tlscredsx509.c',
>    'tlssession.c',
> +  'akcipher.c',
>  ))
>  
>  if nettle.found()
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> new file mode 100644
> index 0000000000..03cc3bf46b
> --- /dev/null
> +++ b/include/crypto/akcipher.h
> @@ -0,0 +1,139 @@
> +/*
> + * QEMU Crypto asymmetric algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: zhenwei pi <pizhenwei@bytedance.com>
> + *
> + * 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 "qemu/typedefs.h"
> +#include "qapi/qapi-types-crypto.h"
> +
> +typedef struct QCryptoAkcipher QCryptoAkcipher;
> +typedef struct QCryptoAkcipherDriver QCryptoAkcipherDriver;
> +
> +struct QCryptoAkcipherDriver {
> +    int (*encrypt)(struct QCryptoAkcipher *akcipher,
> +                   const void *data, size_t data_len,
> +                   void *enc, size_t enc_len, Error **errp);
> +    int (*decrypt)(struct QCryptoAkcipher *akcipher,
> +                   const void *enc, size_t enc_len,
> +                   void *data, size_t data_len, Error **errp);
> +    int (*sign)(struct QCryptoAkcipher *akcipher,
> +                const void *data, size_t data_len,
> +                void *sig, size_t sig_len, Error **errp);
> +    int (*verify)(struct QCryptoAkcipher *akcipher,
> +                  const void *sig, size_t sig_len,
> +                  const void *data, size_t data_len, Error **errp);
> +    int (*free)(struct QCryptoAkcipher *akcipher, Error **errp);
> +};
> +
> +struct QCryptoAkcipher {
> +    QCryptoAkcipherAlgorithm alg;
> +    QCryptoAkcipherKeyType type;
> +    uint8_t *key;
> +    size_t keylen;
> +    int max_plaintext_len;
> +    int max_ciphertext_len;
> +    int max_signature_len;
> +    int max_dgst_len;
> +    QCryptoAkcipherDriver *driver;
> +};

These two structs should be treated as private impl details for
the crypto subsystem, so they should not be exposed in the public
include/crypto/akcipher.h

There needs to be a crypto/akcipherpriv.h file, as we've done with
other APIs in crypto/*priv.h

Also, as with the QAPI def, I'd suggest QCryptoAkCipher as the
capitalization for all the structs.

> +
> +QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
> +                                      QCryptoAkcipherKeyType type,
> +                                      const uint8_t *key, size_t keylen,
> +                                      void *para, Error **errp);

'void *para'  looks pretty dubious.  I suspect this is where 
it needs to be using the discriminated union for the options.
ie

 QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkCipherOptions opts,
                                       QCryptoAkcipherKeyType type,
                                       const uint8_t *key, size_t keylen,
                                       Error **errp);

> +
> +/**
> + * qcrypto_akcipher_encrypt:
> + * @akcipher: akcipher used to do encryption
> + * @data: plaintext pending to be encrypted
> + * @data_len: length of the plaintext, MUST less or equal
> + * akcipher->max_plaintext_len
> + * @enc: buffer to store the ciphertext
> + * @enc_len: the length of ciphertext buffer, usually equals to
> + * akcipher->max_ciphertext_len
> + * @errp: error pointer
> + *
> + * Encrypt data and write ciphertext into enc
> + *
> + * Returns: length of ciphertext if encrypt succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
> +                             const void *data, size_t data_len,
> +                             void *enc, size_t enc_len, Error **errp);

I'd prefer to keep naming matching qcrypto_cipher_encrypt ie

 int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
                              const void *in, size_t in_len,
                              void *out, size_t out_len,
			      Error **errp);

If thue caller njeeds to know about max_ciphertext_len, then we'll
need a API to query that, since the struct should be private.



> +/**
> + * qcrypto_akcipher_sign:
> + * @akcipher: akcipher used to generate signature
> + * @data: data to be signed
> + * @data_len: the length of data
> + * @sig: buffer to store the signature
> + * @sig_len: length of the signature buffer, usually equals to
> + * akcipher->max_signature_len
> + * @errp: error pointer
> + *
> + * Generate signature for data using akcipher
> + *
> + * Returns: length of signature if succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,

Using 'struct' is redundant - use the typedef.

> +                          const void *data, size_t data_len,
> +                          void *sig, size_t sig_len, Error **errp);



> +
> +/**
> + * qcrypto_akcipher_verify:
> + * @akcipher: akcipher used to do verifycation
> + * @sig: pointer to the signature
> + * @sig_len: length of the signature
> + * @data: pointer to original data
> + * @data_len: the length of data
> + * @errp: error pointer
> + *
> + * Verify the signature and the data match or not
> + *
> + * Returns: 0 for succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,

Using 'struct' is redundant - use the typedef.

> +                            const void *sig, size_t sig_len,
> +                            const void *data, size_t data_len, Error **errp);
> +
> +int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);

Using 'struct' is redundant - use the typedef.


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 :|


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 3/6] crypto: Introduce akcipher crypto class
@ 2022-03-23 13:33     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:33 UTC (permalink / raw)
  To: zhenwei pi; +Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, lei he

On Wed, Mar 23, 2022 at 10:49:09AM +0800, zhenwei pi wrote:
> Support basic asymmetric operations: encrypt, decrypt, sign and
> verify.
> 
> Co-developed-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  crypto/akcipher.c         |  78 +++++++++++++++++++++
>  crypto/meson.build        |   1 +
>  include/crypto/akcipher.h | 139 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 218 insertions(+)
>  create mode 100644 crypto/akcipher.c
>  create mode 100644 include/crypto/akcipher.h
> 
> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
> new file mode 100644
> index 0000000000..1e52f2fd76
> --- /dev/null
> +++ b/crypto/akcipher.c
> @@ -0,0 +1,78 @@
> +/*
> + * QEMU Crypto akcipher algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: zhenwei pi <pizhenwei@bytedance.com>
> + *
> + * 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 "qemu/host-utils.h"
> +#include "qapi/error.h"
> +#include "crypto/akcipher.h"
> +
> +QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
> +                                      QCryptoAkcipherKeyType type,
> +                                      const uint8_t *key, size_t keylen,
> +                                      void *para, Error **errp)
> +{
> +    QCryptoAkcipher *akcipher = NULL;
> +
> +    return akcipher;
> +}
> +
> +int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
> +                             const void *data, size_t data_len,
> +                             void *enc, size_t enc_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->encrypt(akcipher, data, data_len, enc, enc_len, errp);
> +}
> +
> +int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
> +                             const void *enc, size_t enc_len,
> +                             void *data, size_t data_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->decrypt(akcipher, enc, enc_len, data, data_len, errp);
> +}
> +
> +int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
> +                          const void *data, size_t data_len,
> +                          void *sig, size_t sig_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->sign(akcipher, data, data_len, sig, sig_len, errp);
> +}
> +
> +int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
> +                            const void *sig, size_t sig_len,
> +                            const void *data, size_t data_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->verify(akcipher, sig, sig_len, data, data_len, errp);
> +}
> +
> +int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->free(akcipher, errp);
> +}
> diff --git a/crypto/meson.build b/crypto/meson.build
> index 19c44bea89..c32b57aeda 100644
> --- a/crypto/meson.build
> +++ b/crypto/meson.build
> @@ -19,6 +19,7 @@ crypto_ss.add(files(
>    'tlscredspsk.c',
>    'tlscredsx509.c',
>    'tlssession.c',
> +  'akcipher.c',
>  ))
>  
>  if nettle.found()
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> new file mode 100644
> index 0000000000..03cc3bf46b
> --- /dev/null
> +++ b/include/crypto/akcipher.h
> @@ -0,0 +1,139 @@
> +/*
> + * QEMU Crypto asymmetric algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: zhenwei pi <pizhenwei@bytedance.com>
> + *
> + * 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 "qemu/typedefs.h"
> +#include "qapi/qapi-types-crypto.h"
> +
> +typedef struct QCryptoAkcipher QCryptoAkcipher;
> +typedef struct QCryptoAkcipherDriver QCryptoAkcipherDriver;
> +
> +struct QCryptoAkcipherDriver {
> +    int (*encrypt)(struct QCryptoAkcipher *akcipher,
> +                   const void *data, size_t data_len,
> +                   void *enc, size_t enc_len, Error **errp);
> +    int (*decrypt)(struct QCryptoAkcipher *akcipher,
> +                   const void *enc, size_t enc_len,
> +                   void *data, size_t data_len, Error **errp);
> +    int (*sign)(struct QCryptoAkcipher *akcipher,
> +                const void *data, size_t data_len,
> +                void *sig, size_t sig_len, Error **errp);
> +    int (*verify)(struct QCryptoAkcipher *akcipher,
> +                  const void *sig, size_t sig_len,
> +                  const void *data, size_t data_len, Error **errp);
> +    int (*free)(struct QCryptoAkcipher *akcipher, Error **errp);
> +};
> +
> +struct QCryptoAkcipher {
> +    QCryptoAkcipherAlgorithm alg;
> +    QCryptoAkcipherKeyType type;
> +    uint8_t *key;
> +    size_t keylen;
> +    int max_plaintext_len;
> +    int max_ciphertext_len;
> +    int max_signature_len;
> +    int max_dgst_len;
> +    QCryptoAkcipherDriver *driver;
> +};

These two structs should be treated as private impl details for
the crypto subsystem, so they should not be exposed in the public
include/crypto/akcipher.h

There needs to be a crypto/akcipherpriv.h file, as we've done with
other APIs in crypto/*priv.h

Also, as with the QAPI def, I'd suggest QCryptoAkCipher as the
capitalization for all the structs.

> +
> +QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
> +                                      QCryptoAkcipherKeyType type,
> +                                      const uint8_t *key, size_t keylen,
> +                                      void *para, Error **errp);

'void *para'  looks pretty dubious.  I suspect this is where 
it needs to be using the discriminated union for the options.
ie

 QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkCipherOptions opts,
                                       QCryptoAkcipherKeyType type,
                                       const uint8_t *key, size_t keylen,
                                       Error **errp);

> +
> +/**
> + * qcrypto_akcipher_encrypt:
> + * @akcipher: akcipher used to do encryption
> + * @data: plaintext pending to be encrypted
> + * @data_len: length of the plaintext, MUST less or equal
> + * akcipher->max_plaintext_len
> + * @enc: buffer to store the ciphertext
> + * @enc_len: the length of ciphertext buffer, usually equals to
> + * akcipher->max_ciphertext_len
> + * @errp: error pointer
> + *
> + * Encrypt data and write ciphertext into enc
> + *
> + * Returns: length of ciphertext if encrypt succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
> +                             const void *data, size_t data_len,
> +                             void *enc, size_t enc_len, Error **errp);

I'd prefer to keep naming matching qcrypto_cipher_encrypt ie

 int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
                              const void *in, size_t in_len,
                              void *out, size_t out_len,
			      Error **errp);

If thue caller njeeds to know about max_ciphertext_len, then we'll
need a API to query that, since the struct should be private.



> +/**
> + * qcrypto_akcipher_sign:
> + * @akcipher: akcipher used to generate signature
> + * @data: data to be signed
> + * @data_len: the length of data
> + * @sig: buffer to store the signature
> + * @sig_len: length of the signature buffer, usually equals to
> + * akcipher->max_signature_len
> + * @errp: error pointer
> + *
> + * Generate signature for data using akcipher
> + *
> + * Returns: length of signature if succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,

Using 'struct' is redundant - use the typedef.

> +                          const void *data, size_t data_len,
> +                          void *sig, size_t sig_len, Error **errp);



> +
> +/**
> + * qcrypto_akcipher_verify:
> + * @akcipher: akcipher used to do verifycation
> + * @sig: pointer to the signature
> + * @sig_len: length of the signature
> + * @data: pointer to original data
> + * @data_len: the length of data
> + * @errp: error pointer
> + *
> + * Verify the signature and the data match or not
> + *
> + * Returns: 0 for succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,

Using 'struct' is redundant - use the typedef.

> +                            const void *sig, size_t sig_len,
> +                            const void *data, size_t data_len, Error **errp);
> +
> +int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);

Using 'struct' is redundant - use the typedef.


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 :|

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 3/6] crypto: Introduce akcipher crypto class
@ 2022-03-23 13:33     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:33 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, lei he

On Wed, Mar 23, 2022 at 10:49:09AM +0800, zhenwei pi wrote:
> Support basic asymmetric operations: encrypt, decrypt, sign and
> verify.
> 
> Co-developed-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  crypto/akcipher.c         |  78 +++++++++++++++++++++
>  crypto/meson.build        |   1 +
>  include/crypto/akcipher.h | 139 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 218 insertions(+)
>  create mode 100644 crypto/akcipher.c
>  create mode 100644 include/crypto/akcipher.h
> 
> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
> new file mode 100644
> index 0000000000..1e52f2fd76
> --- /dev/null
> +++ b/crypto/akcipher.c
> @@ -0,0 +1,78 @@
> +/*
> + * QEMU Crypto akcipher algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: zhenwei pi <pizhenwei@bytedance.com>
> + *
> + * 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 "qemu/host-utils.h"
> +#include "qapi/error.h"
> +#include "crypto/akcipher.h"
> +
> +QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
> +                                      QCryptoAkcipherKeyType type,
> +                                      const uint8_t *key, size_t keylen,
> +                                      void *para, Error **errp)
> +{
> +    QCryptoAkcipher *akcipher = NULL;
> +
> +    return akcipher;
> +}
> +
> +int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
> +                             const void *data, size_t data_len,
> +                             void *enc, size_t enc_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->encrypt(akcipher, data, data_len, enc, enc_len, errp);
> +}
> +
> +int qcrypto_akcipher_decrypt(struct QCryptoAkcipher *akcipher,
> +                             const void *enc, size_t enc_len,
> +                             void *data, size_t data_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->decrypt(akcipher, enc, enc_len, data, data_len, errp);
> +}
> +
> +int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,
> +                          const void *data, size_t data_len,
> +                          void *sig, size_t sig_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->sign(akcipher, data, data_len, sig, sig_len, errp);
> +}
> +
> +int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
> +                            const void *sig, size_t sig_len,
> +                            const void *data, size_t data_len, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->verify(akcipher, sig, sig_len, data, data_len, errp);
> +}
> +
> +int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp)
> +{
> +    const QCryptoAkcipherDriver *drv = akcipher->driver;
> +
> +    return drv->free(akcipher, errp);
> +}
> diff --git a/crypto/meson.build b/crypto/meson.build
> index 19c44bea89..c32b57aeda 100644
> --- a/crypto/meson.build
> +++ b/crypto/meson.build
> @@ -19,6 +19,7 @@ crypto_ss.add(files(
>    'tlscredspsk.c',
>    'tlscredsx509.c',
>    'tlssession.c',
> +  'akcipher.c',
>  ))
>  
>  if nettle.found()
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> new file mode 100644
> index 0000000000..03cc3bf46b
> --- /dev/null
> +++ b/include/crypto/akcipher.h
> @@ -0,0 +1,139 @@
> +/*
> + * QEMU Crypto asymmetric algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: zhenwei pi <pizhenwei@bytedance.com>
> + *
> + * 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 "qemu/typedefs.h"
> +#include "qapi/qapi-types-crypto.h"
> +
> +typedef struct QCryptoAkcipher QCryptoAkcipher;
> +typedef struct QCryptoAkcipherDriver QCryptoAkcipherDriver;
> +
> +struct QCryptoAkcipherDriver {
> +    int (*encrypt)(struct QCryptoAkcipher *akcipher,
> +                   const void *data, size_t data_len,
> +                   void *enc, size_t enc_len, Error **errp);
> +    int (*decrypt)(struct QCryptoAkcipher *akcipher,
> +                   const void *enc, size_t enc_len,
> +                   void *data, size_t data_len, Error **errp);
> +    int (*sign)(struct QCryptoAkcipher *akcipher,
> +                const void *data, size_t data_len,
> +                void *sig, size_t sig_len, Error **errp);
> +    int (*verify)(struct QCryptoAkcipher *akcipher,
> +                  const void *sig, size_t sig_len,
> +                  const void *data, size_t data_len, Error **errp);
> +    int (*free)(struct QCryptoAkcipher *akcipher, Error **errp);
> +};
> +
> +struct QCryptoAkcipher {
> +    QCryptoAkcipherAlgorithm alg;
> +    QCryptoAkcipherKeyType type;
> +    uint8_t *key;
> +    size_t keylen;
> +    int max_plaintext_len;
> +    int max_ciphertext_len;
> +    int max_signature_len;
> +    int max_dgst_len;
> +    QCryptoAkcipherDriver *driver;
> +};

These two structs should be treated as private impl details for
the crypto subsystem, so they should not be exposed in the public
include/crypto/akcipher.h

There needs to be a crypto/akcipherpriv.h file, as we've done with
other APIs in crypto/*priv.h

Also, as with the QAPI def, I'd suggest QCryptoAkCipher as the
capitalization for all the structs.

> +
> +QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
> +                                      QCryptoAkcipherKeyType type,
> +                                      const uint8_t *key, size_t keylen,
> +                                      void *para, Error **errp);

'void *para'  looks pretty dubious.  I suspect this is where 
it needs to be using the discriminated union for the options.
ie

 QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkCipherOptions opts,
                                       QCryptoAkcipherKeyType type,
                                       const uint8_t *key, size_t keylen,
                                       Error **errp);

> +
> +/**
> + * qcrypto_akcipher_encrypt:
> + * @akcipher: akcipher used to do encryption
> + * @data: plaintext pending to be encrypted
> + * @data_len: length of the plaintext, MUST less or equal
> + * akcipher->max_plaintext_len
> + * @enc: buffer to store the ciphertext
> + * @enc_len: the length of ciphertext buffer, usually equals to
> + * akcipher->max_ciphertext_len
> + * @errp: error pointer
> + *
> + * Encrypt data and write ciphertext into enc
> + *
> + * Returns: length of ciphertext if encrypt succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
> +                             const void *data, size_t data_len,
> +                             void *enc, size_t enc_len, Error **errp);

I'd prefer to keep naming matching qcrypto_cipher_encrypt ie

 int qcrypto_akcipher_encrypt(QCryptoAkcipher *akcipher,
                              const void *in, size_t in_len,
                              void *out, size_t out_len,
			      Error **errp);

If thue caller njeeds to know about max_ciphertext_len, then we'll
need a API to query that, since the struct should be private.



> +/**
> + * qcrypto_akcipher_sign:
> + * @akcipher: akcipher used to generate signature
> + * @data: data to be signed
> + * @data_len: the length of data
> + * @sig: buffer to store the signature
> + * @sig_len: length of the signature buffer, usually equals to
> + * akcipher->max_signature_len
> + * @errp: error pointer
> + *
> + * Generate signature for data using akcipher
> + *
> + * Returns: length of signature if succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_sign(struct QCryptoAkcipher *akcipher,

Using 'struct' is redundant - use the typedef.

> +                          const void *data, size_t data_len,
> +                          void *sig, size_t sig_len, Error **errp);



> +
> +/**
> + * qcrypto_akcipher_verify:
> + * @akcipher: akcipher used to do verifycation
> + * @sig: pointer to the signature
> + * @sig_len: length of the signature
> + * @data: pointer to original data
> + * @data_len: the length of data
> + * @errp: error pointer
> + *
> + * Verify the signature and the data match or not
> + *
> + * Returns: 0 for succeed, otherwise -1 is returned
> + */
> +int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,

Using 'struct' is redundant - use the typedef.

> +                            const void *sig, size_t sig_len,
> +                            const void *data, size_t data_len, Error **errp);
> +
> +int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);

Using 'struct' is redundant - use the typedef.


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 :|



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
  2022-03-23  2:49   ` zhenwei pi
  (?)
@ 2022-03-23 13:50     ` Daniel P. Berrangé
  -1 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:50 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, herbert, jasowang, qemu-devel, virtualization,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:10AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
>  crypto/akcipher.c         |   3 +
>  crypto/asn1_decoder.c     | 185 ++++++++++++++
>  crypto/asn1_decoder.h     |  42 +++

Please introduce the asn1 files in a separate commit, and also
provide a unit test to validate them in the same commit.

> diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
> new file mode 100644
> index 0000000000..45b93af772
> --- /dev/null
> +++ b/crypto/akcipher-nettle.c
> @@ -0,0 +1,523 @@
> +/*
> + * QEMU Crypto akcipher algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: lei he <helei.sig11@bytedance.com>
> + *
> + * 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 <stdbool.h>
> +
> +#include <nettle/rsa.h>
> +
> +#include "qemu/osdep.h"
> +#include "qemu/host-utils.h"
> +#include "asn1_decoder.h"
> +#include "crypto/akcipher.h"
> +#include "crypto/random.h"
> +#include "qapi/error.h"
> +#include "sysemu/cryptodev.h"
> +
> +typedef struct QCryptoNettleRsa {
> +    QCryptoAkcipher akcipher;
> +    struct rsa_public_key pub;
> +    struct rsa_private_key priv;
> +    QCryptoRsaPaddingAlgorithm padding_algo;
> +    QCryptoRsaHashAlgorithm hash_algo;
> +} QCryptoNettleRsa;

Call this QCryptoAkCipherNettleRSA

> +
> +struct asn1_parse_ctx {
> +    const uint8_t *data;
> +    size_t dlen;
> +};
> +
> +#define Octet 8
> +
> +static int extract_value(void *p, const uint8_t *data, size_t dlen)
> +{
> +    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
> +    ctx->data = (uint8_t *)data;
> +    ctx->dlen = dlen;
> +
> +    return 0;
> +}
> +
> +static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
> +{
> +    mpz_t *target = (mpz_t *)p;
> +    nettle_mpz_set_str_256_u(*target, dlen, data);
> +
> +    return 0;
> +}
> +
> +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
> +
> +static void qcrypto_nettle_rsa_destroy(void *ptr)
> +{
> +    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
> +    if (!rsa) {
> +        return;
> +    }
> +
> +    rsa_public_key_clear(&rsa->pub);
> +    rsa_private_key_clear(&rsa->priv);
> +    g_free(rsa);
> +}
> +
> +static QCryptoAkcipher *qcrypto_nettle_new_rsa(
> +    QCryptoAkcipherKeyType type,
> +    const uint8_t *key,  size_t keylen,
> +    QCryptoRsaOptions *opt, Error **errp);
> +
> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key,
> +                                             size_t keylen, void *para,
> +                                             Error **errp)
> +{
> +    switch (alg) {
> +    case QCRYPTO_AKCIPHER_ALG_RSA:
> +        return qcrypto_nettle_new_rsa(type, key, keylen,
> +                                      (QCryptoRsaOptions *)para, errp);
> +    default:
> +        error_setg(errp, "Unsupported algorithm: %u", alg);
> +        return NULL;
> +    }
> +
> +    return NULL;
> +}
> +
> +/**
> + * Parse ber encoded rsa private key, asn1 schema:
> + *        RsaPrivKey ::= SEQUENCE {
> + *             version     INTEGER
> + *             n           INTEGER
> + *             e           INTEGER
> + *             d           INTEGER
> + *             p           INTEGER
> + *             q           INTEGER
> + *             e1          INTEGER
> + *             e2          INTEGER
> + *             u           INTEGER
> + *         }
> + */
> +static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
> +                                 const uint8_t *key, size_t keylen)
> +{
> +    struct asn1_parse_ctx ctx;
> +
> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
> +        keylen != 0) {
> +        return -1;
> +    }
> +
> +    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
> +        ctx.dlen != 0) {
> +        return -1;
> +    }
> +
> +    if (!rsa_public_key_prepare(&rsa->pub)) {
> +        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
> +     */
> +    rsa->priv.size = rsa->pub.size;
> +
> +    return 0;
> +}
> +
> +/**
> + * Parse ber encoded rsa pubkey, asn1 schema:
> + *        RsaPrivKey ::= SEQUENCE {
> + *             n           INTEGER
> + *             e           INTEGER
> + *         }
> + */
> +static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
> +                                const uint8_t *key,
> +                                size_t keylen)
> +{
> +    struct asn1_parse_ctx ctx;
> +
> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
> +        keylen != 0) {
> +        return -1;
> +    }
> +
> +    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
> +        ctx.dlen != 0) {
> +        return -1;
> +    }
> +
> +    if (!rsa_public_key_prepare(&rsa->pub)) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}

I'd like to see these APIs for parsing RSA keys split out into
a separate file, crypto/rsakey.{c,h}.  Define a struct to hold
the RSA key parameters so it isn't tied to nettle, allowing
its potential reuse with a gcrypt/gnutls impl of these APIs

> +
> +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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
> +    QCryptoAkcipherKeyType type,
> +    const uint8_t *key, size_t keylen,
> +    QCryptoRsaOptions *opt, Error **errp)
> +{
> +    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
> +    rsa->padding_algo = opt->padding_algo;
> +    rsa->hash_algo = opt->hash_algo;
> +
> +    switch (type) {
> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
> +        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
> +            qcrypto_nettle_rsa_set_akcipher_size(
> +                (QCryptoAkcipher *)rsa, rsa->priv.size);
> +            return (QCryptoAkcipher *)rsa;
> +        }
> +        error_setg(errp, "Failed to parse rsa private key");

This code pattern is back to front of what we would normally
do.  ie I'd expect it to look like this:

         if (parse_rsa_private_key(rsa, key, keylen) != 0) {
             error_setg(errp, "Failed to parse rsa private key");
	     goto error;
         }

         qcrypto_nettle_rsa_set_akcipher_size(
                 (QCryptoAkcipher *)rsa, rsa->priv.size);
         return (QCryptoAkcipher *)rsa;



> +        break;
> +
> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
> +        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
> +            qcrypto_nettle_rsa_set_akcipher_size(
> +                (QCryptoAkcipher *)rsa, rsa->pub.size);
> +            return (QCryptoAkcipher *)rsa;
> +        }
> +        error_setg(errp, "Failed to parse rsa public rsa key");
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unknown akcipher key type %d", type);
> +    }
> +
> +    qcrypto_nettle_rsa_destroy(rsa);
> +    return NULL;
> +}
> +
> +
> +/**
> + * nettle does not provide RSA interfaces without padding,
> + * here we implemented rsa algorithm with nettle/mpz.
> + */

Urgh, this is really unpleasant. I don't want to see QEMU
implementing any further crypto algorithms directly, only
ever consume and wrap impls from external libraries. We've
got a few in QEMU for historical reasons, but don't want
to add more. There are too many ways to mess up crypto
opening the door to subtle timing / side channel attacks,
and crypto impls also cause distributors pain with export
compliance rules.

If nettle doesn't provide an impl without padding, then
simply don't implement it. Report an error if the caller
tries to enable it.

An alternate gcrypt impl of these APIs might allow for
an impl without padding.

> +static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
> +                        size_t data_len, void *enc,
> +                        size_t enc_len, Error **errp)
> +{
> +    mpz_t m;
> +    int ret;
> +
> +    nettle_mpz_init_set_str_256_u(m, data_len, data);
> +    /* (1) Validate 0 <= m < n */
> +    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
> +        error_setg(errp, "Failed to validate input data");
> +        return -1;
> +    }
> +
> +    /* (2) c = m ^ e mod n */
> +    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
> +    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
> +        ret = -1;
> +    } else {
> +        ret = enc_len;
> +        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
> +    }
> +
> +    mpz_clear(m);
> +
> +    return ret;
> +}
> +
> +static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
> +                        const void *enc,
> +                        size_t enc_len,
> +                        void *data,
> +                        size_t data_len,
> +                        Error **errp)
> +{
> +    mpz_t c;
> +    int ret;
> +    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
> +
> +    /* (1) Validate 0 <= c < n */
> +    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
> +        error_setg(errp, "Failed to validate input data");
> +        return -1;
> +    }
> +
> +    /* (2) m = c ^ d mod n */
> +    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
> +    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
> +        ret = -1;
> +    } else {
> +        ret = data_len;
> +        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
> +    }
> +
> +    mpz_clear(c);
> +
> +    return ret;
> +}
> +
> +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
> +{
> +    /* TODO: check result */
> +    qcrypto_random_bytes(out, len, NULL);
> +}
> +
> +static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
> +                                      const void *data, size_t data_len,
> +                                      void *enc, size_t enc_len,
> +                                      Error **errp)
> +{
> +
> +    QCryptoNettleRsa *rsa =
> +        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
> +    mpz_t c;
> +    int enc_ret;
> +
> +    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    switch (rsa->padding_algo) {
> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
> +        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
> +
> +    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
> +        mpz_init(c);
> +        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
> +                              data_len, (uint8_t *)data, c);
> +        if (enc_ret != 1) {
> +            error_setg(errp, "Failed to encrypt");
> +            enc_ret = -1;
> +        } else {
> +            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
> +            enc_ret = enc_len;
> +        }
> +        mpz_clear(c);
> +        return enc_ret;
> +
> +    default:
> +        error_setg(errp, "Unknown padding");
> +        return -1;
> +    }
> +
> +    return -1;
> +}
> +
> +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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +    mpz_t c;
> +    int ret;
> +    if (enc_len > rsa->priv.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    switch (rsa->padding_algo) {
> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
> +        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
> +        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");
> +            ret = -1;
> +        } else {
> +            ret = data_len;
> +        }
> +
> +        mpz_clear(c);
> +        break;
> +
> +    default:
> +        ret = -1;
> +        error_setg(errp, "Unknown padding");
> +    }
> +
> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +    int ret;
> +    mpz_t s;
> +
> +    /**
> +     * The RSA algorithm cannot be used for signature/verification
> +     * without padding.
> +     */
> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
> +        error_setg(errp, "Try to make signature without padding");
> +        return -1;
> +    }
> +
> +    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    mpz_init(s);
> +    switch (rsa->hash_algo) {
> +    case QCRYPTO_RSA_HASH_ALG_MD5:
> +        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
> +        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
> +        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
> +        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unknown hash algorithm");
> +        ret = -1;
> +        goto clear;
> +    }
> +
> +    if (ret != 1) {
> +        error_setg(errp, "Failed to make signature");
> +        ret = -1;
> +        goto clear;
> +    }
> +    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
> +    ret = sig_len;
> +
> +clear:
> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +
> +    int ret;
> +    mpz_t s;
> +
> +    /**
> +     * The RSA algorithm cannot be used for signature/verification
> +     * without padding.
> +     */
> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
> +        error_setg(errp, "Operation not supported");
> +        return -1;
> +    }
> +    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
> +    switch (rsa->hash_algo) {
> +    case QCRYPTO_RSA_HASH_ALG_MD5:
> +        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
> +        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
> +        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
> +        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unsupported hash algorithm");
> +        ret = -1;
> +        goto clear;
> +    }
> +
> +    if (ret != 1) {
> +        error_setg(errp, "Failed to verify");
> +        ret = -1;
> +        goto clear;
> +    }
> +    ret = 0;
> +
> +clear:
> +    mpz_clear(s);
> +
> +    return ret;
> +}
> +
> +static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
> +                                   Error **errp)
> +{
> +    qcrypto_nettle_rsa_destroy(akcipher);
> +    return 0;
> +}
> +
> +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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
> +{
> +    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));

s/g_mallo0/g_new0/

> +    memset(rsa, 0, sizeof(QCryptoNettleRsa));

It is already initialized to zero by the allocator above.

> +    rsa->akcipher.driver = &nettle_rsa;
> +    rsa_public_key_init(&rsa->pub);
> +    rsa_private_key_init(&rsa->priv);

I don't think this method should exist at all though. It only
has one caller, so just put the code inline there.

> +
> +    return rsa;
> +}
> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
> index 1e52f2fd76..b5c04e8424 100644
> --- a/crypto/akcipher.c
> +++ b/crypto/akcipher.c
> @@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
>  {
>      QCryptoAkcipher *akcipher = NULL;
>  
> +    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
> +                                           para, errp);
> +
>      return akcipher;
>  }

Hard-wiring this to use the nettle impl is not at all desirable. It
needs to use a pluggable approach, with a strong preferance to match
the design of the crypto/cipher.c

>  
> diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
> new file mode 100644
> index 0000000000..bfb145e84e
> --- /dev/null
> +++ b/crypto/asn1_decoder.c
> @@ -0,0 +1,185 @@
> +/*
> + * QEMU Crypto akcipher algorithms

This comment is wrong

> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: lei he <helei.sig11@bytedance.com>
> + *
> + * 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 <stdint.h>
> +#include <stddef.h>
> +
> +#include "crypto/asn1_decoder.h"
> +
> +enum ber_type_tag {
> +    ber_type_tag_bool = 0x1,
> +    ber_type_tag_int = 0x2,
> +    ber_type_tag_bit_str = 0x3,
> +    ber_type_tag_oct_str = 0x4,
> +    ber_type_tag_oct_null = 0x5,
> +    ber_type_tag_oct_oid = 0x6,
> +    ber_type_tag_seq = 0x10,
> +    ber_type_tag_set = 0x11,
> +};
> +
> +#define BER_CONSTRUCTED_MASK 0x20
> +#define BER_SHORT_LEN_MASK 0x80
> +
> +static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
> +{
> +    return **data;
> +}
> +
> +static int invoke_callback(BerDecodeCb cb, void *ctx,
> +                           const uint8_t *value, size_t vlen)
> +{
> +    if (!cb) {
> +        return 0;
> +    }
> +
> +    return cb(ctx, value, vlen);
> +}
> +
> +static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
> +                           size_t nbytes)
> +{
> +    *data += nbytes;
> +    *dlen -= nbytes;
> +}
> +
> +static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
> +{
> +    uint8_t val = ber_peek_byte(data, dlen);
> +
> +    ber_cut_nbytes(data, dlen, 1);
> +
> +    return val;
> +}
> +
> +static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
> +                                     BerDecodeCb cb, void *ctx)
> +{
> +    const uint8_t *value;
> +    size_t vlen = 0;
> +    uint8_t byte_count = ber_cut_byte(data, dlen);
> +
> +    /* short format of definite-length */
> +    if (!(byte_count & BER_SHORT_LEN_MASK)) {
> +        if (byte_count > *dlen) {
> +            return -1;
> +        }
> +
> +        value = *data;
> +        vlen = byte_count;
> +        ber_cut_nbytes(data, dlen, vlen);
> +
> +        return invoke_callback(cb, ctx, value, vlen);
> +    }
> +
> +    /* Ignore highest bit */
> +    byte_count &= ~BER_SHORT_LEN_MASK;
> +
> +    /*
> +     * size_t is enough to express the length, although the ber encoding
> +     * standard supports larger length.
> +     */
> +    if (byte_count > sizeof(size_t)) {
> +        return -1;
> +    }
> +
> +    while (byte_count--) {
> +        vlen <<= 8;
> +        vlen += ber_cut_byte(data, dlen);
> +    }
> +
> +    if (vlen > *dlen) {
> +        return -1;
> +    }
> +
> +    value = *data;
> +    ber_cut_nbytes(data, dlen, vlen);
> +
> +    return invoke_callback(cb, ctx, value, vlen);
> +}
> +
> +static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
> +                                       BerDecodeCb cb, void *ctx)
> +{
> +    size_t vlen = 0;
> +    const uint8_t *value;
> +
> +    if (*dlen < 3) {
> +        return -1;
> +    }
> +
> +    /* skip undefinite-length-mask 0x80 */
> +    ber_cut_nbytes(data, dlen, 1);
> +
> +    value = *data;
> +    while (vlen < *dlen) {
> +        if ((*data)[vlen] != 0) {
> +            vlen++;
> +            continue;
> +        }
> +
> +        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
> +            ber_cut_nbytes(data, dlen, vlen + 2);
> +            return invoke_callback(cb, ctx, value, vlen);
> +        }
> +
> +        vlen += 2;
> +    }
> +
> +    return -1;
> +}
> +
> +static int ber_extract_data(const uint8_t **data, size_t *dlen,
> +                            BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t val = ber_peek_byte(data, dlen);
> +
> +    if (val == BER_SHORT_LEN_MASK) {
> +        return ber_extract_undefinite_data(data, dlen, cb, ctx);
> +    }
> +
> +    return ber_extract_definite_data(data, dlen, cb, ctx);
> +}
> +
> +int ber_decode_int(const uint8_t **data, size_t *dlen,
> +                   BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t tag = ber_cut_byte(data, dlen);
> +
> +    /* INTEGER must encoded in primitive-form */
> +    if (tag != ber_type_tag_int) {
> +        return -1;
> +    }
> +
> +    return ber_extract_data(data, dlen, cb, ctx);
> +}
> +
> +int ber_decode_seq(const uint8_t **data, size_t *dlen,
> +                   BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t val = ber_cut_byte(data, dlen);
> +
> +    /* SEQUENCE must use constructed form */
> +    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
> +        return -1;
> +    }
> +
> +    return ber_extract_data(data, dlen, cb, ctx);
> +}

Nettle has some asn1 APIs - can we not use those instead of
implementing all it ourselves ?


> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index 03cc3bf46b..2ec7f0f8d7 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
>  
>  int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
>  
> +#ifdef CONFIG_HOGWEED
> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key, size_t keylen,
> +                                             void *para, Error **errp);
> +#else
> +static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
> +                                             QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key, size_t keylen,
> +                                             void *para, Error **errp)
> +{
> +    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
> +    return NULL;
> +}
> +#endif


These methods are private impl details and should not be in the
akcipher.h public header. This ties back to my earlier comment
about making this akcipher impl pluggable in the same way as
the cipher impl is.


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 :|


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
@ 2022-03-23 13:50     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:50 UTC (permalink / raw)
  To: zhenwei pi; +Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:10AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
>  crypto/akcipher.c         |   3 +
>  crypto/asn1_decoder.c     | 185 ++++++++++++++
>  crypto/asn1_decoder.h     |  42 +++

Please introduce the asn1 files in a separate commit, and also
provide a unit test to validate them in the same commit.

> diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
> new file mode 100644
> index 0000000000..45b93af772
> --- /dev/null
> +++ b/crypto/akcipher-nettle.c
> @@ -0,0 +1,523 @@
> +/*
> + * QEMU Crypto akcipher algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: lei he <helei.sig11@bytedance.com>
> + *
> + * 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 <stdbool.h>
> +
> +#include <nettle/rsa.h>
> +
> +#include "qemu/osdep.h"
> +#include "qemu/host-utils.h"
> +#include "asn1_decoder.h"
> +#include "crypto/akcipher.h"
> +#include "crypto/random.h"
> +#include "qapi/error.h"
> +#include "sysemu/cryptodev.h"
> +
> +typedef struct QCryptoNettleRsa {
> +    QCryptoAkcipher akcipher;
> +    struct rsa_public_key pub;
> +    struct rsa_private_key priv;
> +    QCryptoRsaPaddingAlgorithm padding_algo;
> +    QCryptoRsaHashAlgorithm hash_algo;
> +} QCryptoNettleRsa;

Call this QCryptoAkCipherNettleRSA

> +
> +struct asn1_parse_ctx {
> +    const uint8_t *data;
> +    size_t dlen;
> +};
> +
> +#define Octet 8
> +
> +static int extract_value(void *p, const uint8_t *data, size_t dlen)
> +{
> +    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
> +    ctx->data = (uint8_t *)data;
> +    ctx->dlen = dlen;
> +
> +    return 0;
> +}
> +
> +static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
> +{
> +    mpz_t *target = (mpz_t *)p;
> +    nettle_mpz_set_str_256_u(*target, dlen, data);
> +
> +    return 0;
> +}
> +
> +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
> +
> +static void qcrypto_nettle_rsa_destroy(void *ptr)
> +{
> +    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
> +    if (!rsa) {
> +        return;
> +    }
> +
> +    rsa_public_key_clear(&rsa->pub);
> +    rsa_private_key_clear(&rsa->priv);
> +    g_free(rsa);
> +}
> +
> +static QCryptoAkcipher *qcrypto_nettle_new_rsa(
> +    QCryptoAkcipherKeyType type,
> +    const uint8_t *key,  size_t keylen,
> +    QCryptoRsaOptions *opt, Error **errp);
> +
> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key,
> +                                             size_t keylen, void *para,
> +                                             Error **errp)
> +{
> +    switch (alg) {
> +    case QCRYPTO_AKCIPHER_ALG_RSA:
> +        return qcrypto_nettle_new_rsa(type, key, keylen,
> +                                      (QCryptoRsaOptions *)para, errp);
> +    default:
> +        error_setg(errp, "Unsupported algorithm: %u", alg);
> +        return NULL;
> +    }
> +
> +    return NULL;
> +}
> +
> +/**
> + * Parse ber encoded rsa private key, asn1 schema:
> + *        RsaPrivKey ::= SEQUENCE {
> + *             version     INTEGER
> + *             n           INTEGER
> + *             e           INTEGER
> + *             d           INTEGER
> + *             p           INTEGER
> + *             q           INTEGER
> + *             e1          INTEGER
> + *             e2          INTEGER
> + *             u           INTEGER
> + *         }
> + */
> +static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
> +                                 const uint8_t *key, size_t keylen)
> +{
> +    struct asn1_parse_ctx ctx;
> +
> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
> +        keylen != 0) {
> +        return -1;
> +    }
> +
> +    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
> +        ctx.dlen != 0) {
> +        return -1;
> +    }
> +
> +    if (!rsa_public_key_prepare(&rsa->pub)) {
> +        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
> +     */
> +    rsa->priv.size = rsa->pub.size;
> +
> +    return 0;
> +}
> +
> +/**
> + * Parse ber encoded rsa pubkey, asn1 schema:
> + *        RsaPrivKey ::= SEQUENCE {
> + *             n           INTEGER
> + *             e           INTEGER
> + *         }
> + */
> +static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
> +                                const uint8_t *key,
> +                                size_t keylen)
> +{
> +    struct asn1_parse_ctx ctx;
> +
> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
> +        keylen != 0) {
> +        return -1;
> +    }
> +
> +    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
> +        ctx.dlen != 0) {
> +        return -1;
> +    }
> +
> +    if (!rsa_public_key_prepare(&rsa->pub)) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}

I'd like to see these APIs for parsing RSA keys split out into
a separate file, crypto/rsakey.{c,h}.  Define a struct to hold
the RSA key parameters so it isn't tied to nettle, allowing
its potential reuse with a gcrypt/gnutls impl of these APIs

> +
> +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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
> +    QCryptoAkcipherKeyType type,
> +    const uint8_t *key, size_t keylen,
> +    QCryptoRsaOptions *opt, Error **errp)
> +{
> +    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
> +    rsa->padding_algo = opt->padding_algo;
> +    rsa->hash_algo = opt->hash_algo;
> +
> +    switch (type) {
> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
> +        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
> +            qcrypto_nettle_rsa_set_akcipher_size(
> +                (QCryptoAkcipher *)rsa, rsa->priv.size);
> +            return (QCryptoAkcipher *)rsa;
> +        }
> +        error_setg(errp, "Failed to parse rsa private key");

This code pattern is back to front of what we would normally
do.  ie I'd expect it to look like this:

         if (parse_rsa_private_key(rsa, key, keylen) != 0) {
             error_setg(errp, "Failed to parse rsa private key");
	     goto error;
         }

         qcrypto_nettle_rsa_set_akcipher_size(
                 (QCryptoAkcipher *)rsa, rsa->priv.size);
         return (QCryptoAkcipher *)rsa;



> +        break;
> +
> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
> +        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
> +            qcrypto_nettle_rsa_set_akcipher_size(
> +                (QCryptoAkcipher *)rsa, rsa->pub.size);
> +            return (QCryptoAkcipher *)rsa;
> +        }
> +        error_setg(errp, "Failed to parse rsa public rsa key");
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unknown akcipher key type %d", type);
> +    }
> +
> +    qcrypto_nettle_rsa_destroy(rsa);
> +    return NULL;
> +}
> +
> +
> +/**
> + * nettle does not provide RSA interfaces without padding,
> + * here we implemented rsa algorithm with nettle/mpz.
> + */

Urgh, this is really unpleasant. I don't want to see QEMU
implementing any further crypto algorithms directly, only
ever consume and wrap impls from external libraries. We've
got a few in QEMU for historical reasons, but don't want
to add more. There are too many ways to mess up crypto
opening the door to subtle timing / side channel attacks,
and crypto impls also cause distributors pain with export
compliance rules.

If nettle doesn't provide an impl without padding, then
simply don't implement it. Report an error if the caller
tries to enable it.

An alternate gcrypt impl of these APIs might allow for
an impl without padding.

> +static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
> +                        size_t data_len, void *enc,
> +                        size_t enc_len, Error **errp)
> +{
> +    mpz_t m;
> +    int ret;
> +
> +    nettle_mpz_init_set_str_256_u(m, data_len, data);
> +    /* (1) Validate 0 <= m < n */
> +    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
> +        error_setg(errp, "Failed to validate input data");
> +        return -1;
> +    }
> +
> +    /* (2) c = m ^ e mod n */
> +    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
> +    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
> +        ret = -1;
> +    } else {
> +        ret = enc_len;
> +        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
> +    }
> +
> +    mpz_clear(m);
> +
> +    return ret;
> +}
> +
> +static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
> +                        const void *enc,
> +                        size_t enc_len,
> +                        void *data,
> +                        size_t data_len,
> +                        Error **errp)
> +{
> +    mpz_t c;
> +    int ret;
> +    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
> +
> +    /* (1) Validate 0 <= c < n */
> +    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
> +        error_setg(errp, "Failed to validate input data");
> +        return -1;
> +    }
> +
> +    /* (2) m = c ^ d mod n */
> +    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
> +    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
> +        ret = -1;
> +    } else {
> +        ret = data_len;
> +        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
> +    }
> +
> +    mpz_clear(c);
> +
> +    return ret;
> +}
> +
> +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
> +{
> +    /* TODO: check result */
> +    qcrypto_random_bytes(out, len, NULL);
> +}
> +
> +static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
> +                                      const void *data, size_t data_len,
> +                                      void *enc, size_t enc_len,
> +                                      Error **errp)
> +{
> +
> +    QCryptoNettleRsa *rsa =
> +        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
> +    mpz_t c;
> +    int enc_ret;
> +
> +    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    switch (rsa->padding_algo) {
> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
> +        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
> +
> +    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
> +        mpz_init(c);
> +        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
> +                              data_len, (uint8_t *)data, c);
> +        if (enc_ret != 1) {
> +            error_setg(errp, "Failed to encrypt");
> +            enc_ret = -1;
> +        } else {
> +            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
> +            enc_ret = enc_len;
> +        }
> +        mpz_clear(c);
> +        return enc_ret;
> +
> +    default:
> +        error_setg(errp, "Unknown padding");
> +        return -1;
> +    }
> +
> +    return -1;
> +}
> +
> +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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +    mpz_t c;
> +    int ret;
> +    if (enc_len > rsa->priv.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    switch (rsa->padding_algo) {
> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
> +        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
> +        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");
> +            ret = -1;
> +        } else {
> +            ret = data_len;
> +        }
> +
> +        mpz_clear(c);
> +        break;
> +
> +    default:
> +        ret = -1;
> +        error_setg(errp, "Unknown padding");
> +    }
> +
> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +    int ret;
> +    mpz_t s;
> +
> +    /**
> +     * The RSA algorithm cannot be used for signature/verification
> +     * without padding.
> +     */
> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
> +        error_setg(errp, "Try to make signature without padding");
> +        return -1;
> +    }
> +
> +    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    mpz_init(s);
> +    switch (rsa->hash_algo) {
> +    case QCRYPTO_RSA_HASH_ALG_MD5:
> +        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
> +        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
> +        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
> +        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unknown hash algorithm");
> +        ret = -1;
> +        goto clear;
> +    }
> +
> +    if (ret != 1) {
> +        error_setg(errp, "Failed to make signature");
> +        ret = -1;
> +        goto clear;
> +    }
> +    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
> +    ret = sig_len;
> +
> +clear:
> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +
> +    int ret;
> +    mpz_t s;
> +
> +    /**
> +     * The RSA algorithm cannot be used for signature/verification
> +     * without padding.
> +     */
> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
> +        error_setg(errp, "Operation not supported");
> +        return -1;
> +    }
> +    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
> +    switch (rsa->hash_algo) {
> +    case QCRYPTO_RSA_HASH_ALG_MD5:
> +        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
> +        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
> +        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
> +        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unsupported hash algorithm");
> +        ret = -1;
> +        goto clear;
> +    }
> +
> +    if (ret != 1) {
> +        error_setg(errp, "Failed to verify");
> +        ret = -1;
> +        goto clear;
> +    }
> +    ret = 0;
> +
> +clear:
> +    mpz_clear(s);
> +
> +    return ret;
> +}
> +
> +static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
> +                                   Error **errp)
> +{
> +    qcrypto_nettle_rsa_destroy(akcipher);
> +    return 0;
> +}
> +
> +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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
> +{
> +    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));

s/g_mallo0/g_new0/

> +    memset(rsa, 0, sizeof(QCryptoNettleRsa));

It is already initialized to zero by the allocator above.

> +    rsa->akcipher.driver = &nettle_rsa;
> +    rsa_public_key_init(&rsa->pub);
> +    rsa_private_key_init(&rsa->priv);

I don't think this method should exist at all though. It only
has one caller, so just put the code inline there.

> +
> +    return rsa;
> +}
> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
> index 1e52f2fd76..b5c04e8424 100644
> --- a/crypto/akcipher.c
> +++ b/crypto/akcipher.c
> @@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
>  {
>      QCryptoAkcipher *akcipher = NULL;
>  
> +    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
> +                                           para, errp);
> +
>      return akcipher;
>  }

Hard-wiring this to use the nettle impl is not at all desirable. It
needs to use a pluggable approach, with a strong preferance to match
the design of the crypto/cipher.c

>  
> diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
> new file mode 100644
> index 0000000000..bfb145e84e
> --- /dev/null
> +++ b/crypto/asn1_decoder.c
> @@ -0,0 +1,185 @@
> +/*
> + * QEMU Crypto akcipher algorithms

This comment is wrong

> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: lei he <helei.sig11@bytedance.com>
> + *
> + * 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 <stdint.h>
> +#include <stddef.h>
> +
> +#include "crypto/asn1_decoder.h"
> +
> +enum ber_type_tag {
> +    ber_type_tag_bool = 0x1,
> +    ber_type_tag_int = 0x2,
> +    ber_type_tag_bit_str = 0x3,
> +    ber_type_tag_oct_str = 0x4,
> +    ber_type_tag_oct_null = 0x5,
> +    ber_type_tag_oct_oid = 0x6,
> +    ber_type_tag_seq = 0x10,
> +    ber_type_tag_set = 0x11,
> +};
> +
> +#define BER_CONSTRUCTED_MASK 0x20
> +#define BER_SHORT_LEN_MASK 0x80
> +
> +static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
> +{
> +    return **data;
> +}
> +
> +static int invoke_callback(BerDecodeCb cb, void *ctx,
> +                           const uint8_t *value, size_t vlen)
> +{
> +    if (!cb) {
> +        return 0;
> +    }
> +
> +    return cb(ctx, value, vlen);
> +}
> +
> +static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
> +                           size_t nbytes)
> +{
> +    *data += nbytes;
> +    *dlen -= nbytes;
> +}
> +
> +static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
> +{
> +    uint8_t val = ber_peek_byte(data, dlen);
> +
> +    ber_cut_nbytes(data, dlen, 1);
> +
> +    return val;
> +}
> +
> +static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
> +                                     BerDecodeCb cb, void *ctx)
> +{
> +    const uint8_t *value;
> +    size_t vlen = 0;
> +    uint8_t byte_count = ber_cut_byte(data, dlen);
> +
> +    /* short format of definite-length */
> +    if (!(byte_count & BER_SHORT_LEN_MASK)) {
> +        if (byte_count > *dlen) {
> +            return -1;
> +        }
> +
> +        value = *data;
> +        vlen = byte_count;
> +        ber_cut_nbytes(data, dlen, vlen);
> +
> +        return invoke_callback(cb, ctx, value, vlen);
> +    }
> +
> +    /* Ignore highest bit */
> +    byte_count &= ~BER_SHORT_LEN_MASK;
> +
> +    /*
> +     * size_t is enough to express the length, although the ber encoding
> +     * standard supports larger length.
> +     */
> +    if (byte_count > sizeof(size_t)) {
> +        return -1;
> +    }
> +
> +    while (byte_count--) {
> +        vlen <<= 8;
> +        vlen += ber_cut_byte(data, dlen);
> +    }
> +
> +    if (vlen > *dlen) {
> +        return -1;
> +    }
> +
> +    value = *data;
> +    ber_cut_nbytes(data, dlen, vlen);
> +
> +    return invoke_callback(cb, ctx, value, vlen);
> +}
> +
> +static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
> +                                       BerDecodeCb cb, void *ctx)
> +{
> +    size_t vlen = 0;
> +    const uint8_t *value;
> +
> +    if (*dlen < 3) {
> +        return -1;
> +    }
> +
> +    /* skip undefinite-length-mask 0x80 */
> +    ber_cut_nbytes(data, dlen, 1);
> +
> +    value = *data;
> +    while (vlen < *dlen) {
> +        if ((*data)[vlen] != 0) {
> +            vlen++;
> +            continue;
> +        }
> +
> +        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
> +            ber_cut_nbytes(data, dlen, vlen + 2);
> +            return invoke_callback(cb, ctx, value, vlen);
> +        }
> +
> +        vlen += 2;
> +    }
> +
> +    return -1;
> +}
> +
> +static int ber_extract_data(const uint8_t **data, size_t *dlen,
> +                            BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t val = ber_peek_byte(data, dlen);
> +
> +    if (val == BER_SHORT_LEN_MASK) {
> +        return ber_extract_undefinite_data(data, dlen, cb, ctx);
> +    }
> +
> +    return ber_extract_definite_data(data, dlen, cb, ctx);
> +}
> +
> +int ber_decode_int(const uint8_t **data, size_t *dlen,
> +                   BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t tag = ber_cut_byte(data, dlen);
> +
> +    /* INTEGER must encoded in primitive-form */
> +    if (tag != ber_type_tag_int) {
> +        return -1;
> +    }
> +
> +    return ber_extract_data(data, dlen, cb, ctx);
> +}
> +
> +int ber_decode_seq(const uint8_t **data, size_t *dlen,
> +                   BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t val = ber_cut_byte(data, dlen);
> +
> +    /* SEQUENCE must use constructed form */
> +    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
> +        return -1;
> +    }
> +
> +    return ber_extract_data(data, dlen, cb, ctx);
> +}

Nettle has some asn1 APIs - can we not use those instead of
implementing all it ourselves ?


> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index 03cc3bf46b..2ec7f0f8d7 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
>  
>  int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
>  
> +#ifdef CONFIG_HOGWEED
> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key, size_t keylen,
> +                                             void *para, Error **errp);
> +#else
> +static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
> +                                             QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key, size_t keylen,
> +                                             void *para, Error **errp)
> +{
> +    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
> +    return NULL;
> +}
> +#endif


These methods are private impl details and should not be in the
akcipher.h public header. This ties back to my earlier comment
about making this akcipher impl pluggable in the same way as
the cipher impl is.


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 :|

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
@ 2022-03-23 13:50     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 13:50 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:10AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
>  crypto/akcipher.c         |   3 +
>  crypto/asn1_decoder.c     | 185 ++++++++++++++
>  crypto/asn1_decoder.h     |  42 +++

Please introduce the asn1 files in a separate commit, and also
provide a unit test to validate them in the same commit.

> diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
> new file mode 100644
> index 0000000000..45b93af772
> --- /dev/null
> +++ b/crypto/akcipher-nettle.c
> @@ -0,0 +1,523 @@
> +/*
> + * QEMU Crypto akcipher algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: lei he <helei.sig11@bytedance.com>
> + *
> + * 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 <stdbool.h>
> +
> +#include <nettle/rsa.h>
> +
> +#include "qemu/osdep.h"
> +#include "qemu/host-utils.h"
> +#include "asn1_decoder.h"
> +#include "crypto/akcipher.h"
> +#include "crypto/random.h"
> +#include "qapi/error.h"
> +#include "sysemu/cryptodev.h"
> +
> +typedef struct QCryptoNettleRsa {
> +    QCryptoAkcipher akcipher;
> +    struct rsa_public_key pub;
> +    struct rsa_private_key priv;
> +    QCryptoRsaPaddingAlgorithm padding_algo;
> +    QCryptoRsaHashAlgorithm hash_algo;
> +} QCryptoNettleRsa;

Call this QCryptoAkCipherNettleRSA

> +
> +struct asn1_parse_ctx {
> +    const uint8_t *data;
> +    size_t dlen;
> +};
> +
> +#define Octet 8
> +
> +static int extract_value(void *p, const uint8_t *data, size_t dlen)
> +{
> +    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
> +    ctx->data = (uint8_t *)data;
> +    ctx->dlen = dlen;
> +
> +    return 0;
> +}
> +
> +static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
> +{
> +    mpz_t *target = (mpz_t *)p;
> +    nettle_mpz_set_str_256_u(*target, dlen, data);
> +
> +    return 0;
> +}
> +
> +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
> +
> +static void qcrypto_nettle_rsa_destroy(void *ptr)
> +{
> +    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
> +    if (!rsa) {
> +        return;
> +    }
> +
> +    rsa_public_key_clear(&rsa->pub);
> +    rsa_private_key_clear(&rsa->priv);
> +    g_free(rsa);
> +}
> +
> +static QCryptoAkcipher *qcrypto_nettle_new_rsa(
> +    QCryptoAkcipherKeyType type,
> +    const uint8_t *key,  size_t keylen,
> +    QCryptoRsaOptions *opt, Error **errp);
> +
> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key,
> +                                             size_t keylen, void *para,
> +                                             Error **errp)
> +{
> +    switch (alg) {
> +    case QCRYPTO_AKCIPHER_ALG_RSA:
> +        return qcrypto_nettle_new_rsa(type, key, keylen,
> +                                      (QCryptoRsaOptions *)para, errp);
> +    default:
> +        error_setg(errp, "Unsupported algorithm: %u", alg);
> +        return NULL;
> +    }
> +
> +    return NULL;
> +}
> +
> +/**
> + * Parse ber encoded rsa private key, asn1 schema:
> + *        RsaPrivKey ::= SEQUENCE {
> + *             version     INTEGER
> + *             n           INTEGER
> + *             e           INTEGER
> + *             d           INTEGER
> + *             p           INTEGER
> + *             q           INTEGER
> + *             e1          INTEGER
> + *             e2          INTEGER
> + *             u           INTEGER
> + *         }
> + */
> +static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
> +                                 const uint8_t *key, size_t keylen)
> +{
> +    struct asn1_parse_ctx ctx;
> +
> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
> +        keylen != 0) {
> +        return -1;
> +    }
> +
> +    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
> +        ctx.dlen != 0) {
> +        return -1;
> +    }
> +
> +    if (!rsa_public_key_prepare(&rsa->pub)) {
> +        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
> +     */
> +    rsa->priv.size = rsa->pub.size;
> +
> +    return 0;
> +}
> +
> +/**
> + * Parse ber encoded rsa pubkey, asn1 schema:
> + *        RsaPrivKey ::= SEQUENCE {
> + *             n           INTEGER
> + *             e           INTEGER
> + *         }
> + */
> +static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
> +                                const uint8_t *key,
> +                                size_t keylen)
> +{
> +    struct asn1_parse_ctx ctx;
> +
> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
> +        keylen != 0) {
> +        return -1;
> +    }
> +
> +    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
> +        ctx.dlen != 0) {
> +        return -1;
> +    }
> +
> +    if (!rsa_public_key_prepare(&rsa->pub)) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}

I'd like to see these APIs for parsing RSA keys split out into
a separate file, crypto/rsakey.{c,h}.  Define a struct to hold
the RSA key parameters so it isn't tied to nettle, allowing
its potential reuse with a gcrypt/gnutls impl of these APIs

> +
> +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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
> +    QCryptoAkcipherKeyType type,
> +    const uint8_t *key, size_t keylen,
> +    QCryptoRsaOptions *opt, Error **errp)
> +{
> +    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
> +    rsa->padding_algo = opt->padding_algo;
> +    rsa->hash_algo = opt->hash_algo;
> +
> +    switch (type) {
> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
> +        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
> +            qcrypto_nettle_rsa_set_akcipher_size(
> +                (QCryptoAkcipher *)rsa, rsa->priv.size);
> +            return (QCryptoAkcipher *)rsa;
> +        }
> +        error_setg(errp, "Failed to parse rsa private key");

This code pattern is back to front of what we would normally
do.  ie I'd expect it to look like this:

         if (parse_rsa_private_key(rsa, key, keylen) != 0) {
             error_setg(errp, "Failed to parse rsa private key");
	     goto error;
         }

         qcrypto_nettle_rsa_set_akcipher_size(
                 (QCryptoAkcipher *)rsa, rsa->priv.size);
         return (QCryptoAkcipher *)rsa;



> +        break;
> +
> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
> +        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
> +            qcrypto_nettle_rsa_set_akcipher_size(
> +                (QCryptoAkcipher *)rsa, rsa->pub.size);
> +            return (QCryptoAkcipher *)rsa;
> +        }
> +        error_setg(errp, "Failed to parse rsa public rsa key");
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unknown akcipher key type %d", type);
> +    }
> +
> +    qcrypto_nettle_rsa_destroy(rsa);
> +    return NULL;
> +}
> +
> +
> +/**
> + * nettle does not provide RSA interfaces without padding,
> + * here we implemented rsa algorithm with nettle/mpz.
> + */

Urgh, this is really unpleasant. I don't want to see QEMU
implementing any further crypto algorithms directly, only
ever consume and wrap impls from external libraries. We've
got a few in QEMU for historical reasons, but don't want
to add more. There are too many ways to mess up crypto
opening the door to subtle timing / side channel attacks,
and crypto impls also cause distributors pain with export
compliance rules.

If nettle doesn't provide an impl without padding, then
simply don't implement it. Report an error if the caller
tries to enable it.

An alternate gcrypt impl of these APIs might allow for
an impl without padding.

> +static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
> +                        size_t data_len, void *enc,
> +                        size_t enc_len, Error **errp)
> +{
> +    mpz_t m;
> +    int ret;
> +
> +    nettle_mpz_init_set_str_256_u(m, data_len, data);
> +    /* (1) Validate 0 <= m < n */
> +    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
> +        error_setg(errp, "Failed to validate input data");
> +        return -1;
> +    }
> +
> +    /* (2) c = m ^ e mod n */
> +    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
> +    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
> +        ret = -1;
> +    } else {
> +        ret = enc_len;
> +        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
> +    }
> +
> +    mpz_clear(m);
> +
> +    return ret;
> +}
> +
> +static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
> +                        const void *enc,
> +                        size_t enc_len,
> +                        void *data,
> +                        size_t data_len,
> +                        Error **errp)
> +{
> +    mpz_t c;
> +    int ret;
> +    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
> +
> +    /* (1) Validate 0 <= c < n */
> +    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
> +        error_setg(errp, "Failed to validate input data");
> +        return -1;
> +    }
> +
> +    /* (2) m = c ^ d mod n */
> +    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
> +    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
> +        ret = -1;
> +    } else {
> +        ret = data_len;
> +        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
> +    }
> +
> +    mpz_clear(c);
> +
> +    return ret;
> +}
> +
> +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
> +{
> +    /* TODO: check result */
> +    qcrypto_random_bytes(out, len, NULL);
> +}
> +
> +static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
> +                                      const void *data, size_t data_len,
> +                                      void *enc, size_t enc_len,
> +                                      Error **errp)
> +{
> +
> +    QCryptoNettleRsa *rsa =
> +        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
> +    mpz_t c;
> +    int enc_ret;
> +
> +    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    switch (rsa->padding_algo) {
> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
> +        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
> +
> +    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
> +        mpz_init(c);
> +        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
> +                              data_len, (uint8_t *)data, c);
> +        if (enc_ret != 1) {
> +            error_setg(errp, "Failed to encrypt");
> +            enc_ret = -1;
> +        } else {
> +            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
> +            enc_ret = enc_len;
> +        }
> +        mpz_clear(c);
> +        return enc_ret;
> +
> +    default:
> +        error_setg(errp, "Unknown padding");
> +        return -1;
> +    }
> +
> +    return -1;
> +}
> +
> +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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +    mpz_t c;
> +    int ret;
> +    if (enc_len > rsa->priv.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    switch (rsa->padding_algo) {
> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
> +        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
> +        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");
> +            ret = -1;
> +        } else {
> +            ret = data_len;
> +        }
> +
> +        mpz_clear(c);
> +        break;
> +
> +    default:
> +        ret = -1;
> +        error_setg(errp, "Unknown padding");
> +    }
> +
> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +    int ret;
> +    mpz_t s;
> +
> +    /**
> +     * The RSA algorithm cannot be used for signature/verification
> +     * without padding.
> +     */
> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
> +        error_setg(errp, "Try to make signature without padding");
> +        return -1;
> +    }
> +
> +    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    mpz_init(s);
> +    switch (rsa->hash_algo) {
> +    case QCRYPTO_RSA_HASH_ALG_MD5:
> +        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
> +        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
> +        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
> +        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unknown hash algorithm");
> +        ret = -1;
> +        goto clear;
> +    }
> +
> +    if (ret != 1) {
> +        error_setg(errp, "Failed to make signature");
> +        ret = -1;
> +        goto clear;
> +    }
> +    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
> +    ret = sig_len;
> +
> +clear:
> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
> +
> +    int ret;
> +    mpz_t s;
> +
> +    /**
> +     * The RSA algorithm cannot be used for signature/verification
> +     * without padding.
> +     */
> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
> +        error_setg(errp, "Operation not supported");
> +        return -1;
> +    }
> +    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
> +        error_setg(errp, "Invalid buffer size");
> +        return -1;
> +    }
> +
> +    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
> +    switch (rsa->hash_algo) {
> +    case QCRYPTO_RSA_HASH_ALG_MD5:
> +        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
> +        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
> +        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
> +        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
> +        break;
> +
> +    default:
> +        error_setg(errp, "Unsupported hash algorithm");
> +        ret = -1;
> +        goto clear;
> +    }
> +
> +    if (ret != 1) {
> +        error_setg(errp, "Failed to verify");
> +        ret = -1;
> +        goto clear;
> +    }
> +    ret = 0;
> +
> +clear:
> +    mpz_clear(s);
> +
> +    return ret;
> +}
> +
> +static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
> +                                   Error **errp)
> +{
> +    qcrypto_nettle_rsa_destroy(akcipher);
> +    return 0;
> +}
> +
> +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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
> +{
> +    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));

s/g_mallo0/g_new0/

> +    memset(rsa, 0, sizeof(QCryptoNettleRsa));

It is already initialized to zero by the allocator above.

> +    rsa->akcipher.driver = &nettle_rsa;
> +    rsa_public_key_init(&rsa->pub);
> +    rsa_private_key_init(&rsa->priv);

I don't think this method should exist at all though. It only
has one caller, so just put the code inline there.

> +
> +    return rsa;
> +}
> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
> index 1e52f2fd76..b5c04e8424 100644
> --- a/crypto/akcipher.c
> +++ b/crypto/akcipher.c
> @@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
>  {
>      QCryptoAkcipher *akcipher = NULL;
>  
> +    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
> +                                           para, errp);
> +
>      return akcipher;
>  }

Hard-wiring this to use the nettle impl is not at all desirable. It
needs to use a pluggable approach, with a strong preferance to match
the design of the crypto/cipher.c

>  
> diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
> new file mode 100644
> index 0000000000..bfb145e84e
> --- /dev/null
> +++ b/crypto/asn1_decoder.c
> @@ -0,0 +1,185 @@
> +/*
> + * QEMU Crypto akcipher algorithms

This comment is wrong

> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: lei he <helei.sig11@bytedance.com>
> + *
> + * 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 <stdint.h>
> +#include <stddef.h>
> +
> +#include "crypto/asn1_decoder.h"
> +
> +enum ber_type_tag {
> +    ber_type_tag_bool = 0x1,
> +    ber_type_tag_int = 0x2,
> +    ber_type_tag_bit_str = 0x3,
> +    ber_type_tag_oct_str = 0x4,
> +    ber_type_tag_oct_null = 0x5,
> +    ber_type_tag_oct_oid = 0x6,
> +    ber_type_tag_seq = 0x10,
> +    ber_type_tag_set = 0x11,
> +};
> +
> +#define BER_CONSTRUCTED_MASK 0x20
> +#define BER_SHORT_LEN_MASK 0x80
> +
> +static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
> +{
> +    return **data;
> +}
> +
> +static int invoke_callback(BerDecodeCb cb, void *ctx,
> +                           const uint8_t *value, size_t vlen)
> +{
> +    if (!cb) {
> +        return 0;
> +    }
> +
> +    return cb(ctx, value, vlen);
> +}
> +
> +static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
> +                           size_t nbytes)
> +{
> +    *data += nbytes;
> +    *dlen -= nbytes;
> +}
> +
> +static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
> +{
> +    uint8_t val = ber_peek_byte(data, dlen);
> +
> +    ber_cut_nbytes(data, dlen, 1);
> +
> +    return val;
> +}
> +
> +static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
> +                                     BerDecodeCb cb, void *ctx)
> +{
> +    const uint8_t *value;
> +    size_t vlen = 0;
> +    uint8_t byte_count = ber_cut_byte(data, dlen);
> +
> +    /* short format of definite-length */
> +    if (!(byte_count & BER_SHORT_LEN_MASK)) {
> +        if (byte_count > *dlen) {
> +            return -1;
> +        }
> +
> +        value = *data;
> +        vlen = byte_count;
> +        ber_cut_nbytes(data, dlen, vlen);
> +
> +        return invoke_callback(cb, ctx, value, vlen);
> +    }
> +
> +    /* Ignore highest bit */
> +    byte_count &= ~BER_SHORT_LEN_MASK;
> +
> +    /*
> +     * size_t is enough to express the length, although the ber encoding
> +     * standard supports larger length.
> +     */
> +    if (byte_count > sizeof(size_t)) {
> +        return -1;
> +    }
> +
> +    while (byte_count--) {
> +        vlen <<= 8;
> +        vlen += ber_cut_byte(data, dlen);
> +    }
> +
> +    if (vlen > *dlen) {
> +        return -1;
> +    }
> +
> +    value = *data;
> +    ber_cut_nbytes(data, dlen, vlen);
> +
> +    return invoke_callback(cb, ctx, value, vlen);
> +}
> +
> +static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
> +                                       BerDecodeCb cb, void *ctx)
> +{
> +    size_t vlen = 0;
> +    const uint8_t *value;
> +
> +    if (*dlen < 3) {
> +        return -1;
> +    }
> +
> +    /* skip undefinite-length-mask 0x80 */
> +    ber_cut_nbytes(data, dlen, 1);
> +
> +    value = *data;
> +    while (vlen < *dlen) {
> +        if ((*data)[vlen] != 0) {
> +            vlen++;
> +            continue;
> +        }
> +
> +        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
> +            ber_cut_nbytes(data, dlen, vlen + 2);
> +            return invoke_callback(cb, ctx, value, vlen);
> +        }
> +
> +        vlen += 2;
> +    }
> +
> +    return -1;
> +}
> +
> +static int ber_extract_data(const uint8_t **data, size_t *dlen,
> +                            BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t val = ber_peek_byte(data, dlen);
> +
> +    if (val == BER_SHORT_LEN_MASK) {
> +        return ber_extract_undefinite_data(data, dlen, cb, ctx);
> +    }
> +
> +    return ber_extract_definite_data(data, dlen, cb, ctx);
> +}
> +
> +int ber_decode_int(const uint8_t **data, size_t *dlen,
> +                   BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t tag = ber_cut_byte(data, dlen);
> +
> +    /* INTEGER must encoded in primitive-form */
> +    if (tag != ber_type_tag_int) {
> +        return -1;
> +    }
> +
> +    return ber_extract_data(data, dlen, cb, ctx);
> +}
> +
> +int ber_decode_seq(const uint8_t **data, size_t *dlen,
> +                   BerDecodeCb cb, void *ctx)
> +{
> +    uint8_t val = ber_cut_byte(data, dlen);
> +
> +    /* SEQUENCE must use constructed form */
> +    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
> +        return -1;
> +    }
> +
> +    return ber_extract_data(data, dlen, cb, ctx);
> +}

Nettle has some asn1 APIs - can we not use those instead of
implementing all it ourselves ?


> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index 03cc3bf46b..2ec7f0f8d7 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
>  
>  int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
>  
> +#ifdef CONFIG_HOGWEED
> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key, size_t keylen,
> +                                             void *para, Error **errp);
> +#else
> +static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
> +                                             QCryptoAkcipherAlgorithm alg,
> +                                             QCryptoAkcipherKeyType type,
> +                                             const uint8_t *key, size_t keylen,
> +                                             void *para, Error **errp)
> +{
> +    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
> +    return NULL;
> +}
> +#endif


These methods are private impl details and should not be in the
akcipher.h public header. This ties back to my earlier comment
about making this akcipher impl pluggable in the same way as
the cipher impl is.


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 :|



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
  2022-03-23 12:36   ` Michael S. Tsirkin
  (?)
@ 2022-03-23 14:37     ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23 14:37 UTC (permalink / raw)
  To: Michael S. Tsirkin, Daniel P. Berrangé
  Cc: arei.gonglei, jasowang, virtualization, qemu-devel, linux-crypto,
	herbert, helei.sig11

On 3/23/22 20:36, Michael S. Tsirkin wrote:
> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>> 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
> 
> Thanks!
> I tagged this but qemu is in freeze. If possible pls ping or
> repost after the release to help make sure I don't lose it.
> 
Hi,

Daniel has started to review this patchset, according to Daniel's 
important suggestion, I'll rework this feature and post the next version 
later.

Thanks a lot!

-- 
zhenwei pi

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23 14:37     ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23 14:37 UTC (permalink / raw)
  To: Michael S. Tsirkin, Daniel P. Berrangé
  Cc: herbert, qemu-devel, virtualization, linux-crypto, helei.sig11

On 3/23/22 20:36, Michael S. Tsirkin wrote:
> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>> 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
> 
> Thanks!
> I tagged this but qemu is in freeze. If possible pls ping or
> repost after the release to help make sure I don't lose it.
> 
Hi,

Daniel has started to review this patchset, according to Daniel's 
important suggestion, I'll rework this feature and post the next version 
later.

Thanks a lot!

-- 
zhenwei pi
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23 14:37     ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23 14:37 UTC (permalink / raw)
  To: Michael S. Tsirkin, Daniel P. Berrangé
  Cc: herbert, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, helei.sig11

On 3/23/22 20:36, Michael S. Tsirkin wrote:
> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>> 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
> 
> Thanks!
> I tagged this but qemu is in freeze. If possible pls ping or
> repost after the release to help make sure I don't lose it.
> 
Hi,

Daniel has started to review this patchset, according to Daniel's 
important suggestion, I'll rework this feature and post the next version 
later.

Thanks a lot!

-- 
zhenwei pi


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
  2022-03-23  2:49   ` zhenwei pi
  (?)
@ 2022-03-23 15:00     ` Daniel P. Berrangé
  -1 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:00 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, herbert, jasowang, qemu-devel, virtualization,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:08AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce akcipher types, also include RSA & ECDSA related types.
> 
> Signed-off-by: Lei He <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 1ec54c15ca..d44c38e3b1 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -540,3 +540,89 @@
>    'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
>              '*sanity-check': 'bool',
>              '*passwordid': 'str' } }
> +##
> +# @QCryptoAkcipherAlgorithm:
> +#
> +# The supported algorithms for asymmetric encryption ciphers
> +#
> +# @rsa: RSA algorithm
> +# @ecdsa: ECDSA algorithm
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherAlgorithm',
> +  'prefix': 'QCRYPTO_AKCIPHER_ALG',
> +  'data': ['rsa', 'ecdsa']}

What were your intentions wrt  ecdsa - the nettle impl in this patch
series doesn't appear to actually support ecdsa. Are you intending to
add this in later versions of this patch series, or do it as separate
work at a later date ?


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 :|


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
@ 2022-03-23 15:00     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:00 UTC (permalink / raw)
  To: zhenwei pi; +Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:08AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce akcipher types, also include RSA & ECDSA related types.
> 
> Signed-off-by: Lei He <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 1ec54c15ca..d44c38e3b1 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -540,3 +540,89 @@
>    'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
>              '*sanity-check': 'bool',
>              '*passwordid': 'str' } }
> +##
> +# @QCryptoAkcipherAlgorithm:
> +#
> +# The supported algorithms for asymmetric encryption ciphers
> +#
> +# @rsa: RSA algorithm
> +# @ecdsa: ECDSA algorithm
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherAlgorithm',
> +  'prefix': 'QCRYPTO_AKCIPHER_ALG',
> +  'data': ['rsa', 'ecdsa']}

What were your intentions wrt  ecdsa - the nettle impl in this patch
series doesn't appear to actually support ecdsa. Are you intending to
add this in later versions of this patch series, or do it as separate
work at a later date ?


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 :|

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi
@ 2022-03-23 15:00     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:00 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:08AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Introduce akcipher types, also include RSA & ECDSA related types.
> 
> Signed-off-by: Lei He <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 1ec54c15ca..d44c38e3b1 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -540,3 +540,89 @@
>    'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
>              '*sanity-check': 'bool',
>              '*passwordid': 'str' } }
> +##
> +# @QCryptoAkcipherAlgorithm:
> +#
> +# The supported algorithms for asymmetric encryption ciphers
> +#
> +# @rsa: RSA algorithm
> +# @ecdsa: ECDSA algorithm
> +#
> +# Since: 7.0
> +##
> +{ 'enum': 'QCryptoAkcipherAlgorithm',
> +  'prefix': 'QCRYPTO_AKCIPHER_ALG',
> +  'data': ['rsa', 'ecdsa']}

What were your intentions wrt  ecdsa - the nettle impl in this patch
series doesn't appear to actually support ecdsa. Are you intending to
add this in later versions of this patch series, or do it as separate
work at a later date ?


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 :|



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 5/6] tests/crypto: Add test suite for crypto akcipher
  2022-03-23  2:49   ` zhenwei pi
  (?)
@ 2022-03-23 15:10     ` Daniel P. Berrangé
  -1 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:10 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, herbert, jasowang, qemu-devel, virtualization,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:11AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Add unit test and benchmark test for crypto akcipher.
> 
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  tests/bench/benchmark-crypto-akcipher.c | 163 ++++++
>  tests/bench/meson.build                 |   6 +
>  tests/bench/test_akcipher_keys.inc      | 277 +++++++++
>  tests/unit/meson.build                  |   1 +
>  tests/unit/test-crypto-akcipher.c       | 715 ++++++++++++++++++++++++
>  5 files changed, 1162 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..152fed8d73
> --- /dev/null
> +++ b/tests/bench/benchmark-crypto-akcipher.c
> @@ -0,0 +1,163 @@
> +/*
> + * QEMU Crypto cipher speed benchmark
> + *
> + * Copyright (c) 2022 Bytedance
> + *
> + * Authors:
> + *    lei he <helei.sig11@bytedance.com>
> + *
> + * 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,
> +                                            QCryptoRsaHashAlgorithm hash)
> +{
> +    QCryptoRsaOptions opt;
> +    QCryptoAkcipher *rsa;
> +    Error *err = NULL;
> +
> +    opt.padding_algo = padding;
> +    opt.hash_algo = hash;
> +    rsa = qcrypto_akcipher_new(QCRYPTO_AKCIPHER_ALG_RSA,
> +                               QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
> +                               priv_key, keylen, &opt, &err);
> +
> +    g_assert(rsa != NULL);
> +    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 40
> +#define DURATION_SECONDS 10
> +#define padding QCRYPTO_RSA_PADDING_ALG_PKCS1
> +#define hash QCRYPTO_RSA_HASH_ALG_SHA1

'Byte' 'padding' and 'duration' are 

> +
> +    Error *err = NULL;
> +    QCryptoAkcipher *rsa;
> +    uint8_t *dgst, *signature;
> +    size_t count;
> +
> +    rsa = create_rsa_akcipher(priv_key, keylen, padding, hash);
> +
> +    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),
> +                   QCryptoRsaHashAlgorithm_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, &err) > 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),
> +                   QCryptoRsaHashAlgorithm_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),
> +                   QCryptoRsaHashAlgorithm_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, &err) == 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),
> +                   QCryptoRsaHashAlgorithm_str(hash),
> +                   count, g_test_timer_last(),
> +                   (double)count / g_test_timer_last());
> +
> +    g_assert(qcrypto_akcipher_free(rsa, &err) == 0);
> +    g_free(dgst);
> +    g_free(signature);
> +}
> +
> +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..92491538f9 100644
> --- a/tests/bench/meson.build
> +++ b/tests/bench/meson.build
> @@ -23,6 +23,12 @@ if have_block
>    }
>  endif
>  
> +if nettle.found() and hogweed.found()
> +    benchs += {
> +        'benchmark-crypto-akcipher': [crypto],
> +    }
> +endif
> +
>  foreach bench_name, deps: benchs
>    exe = executable(bench_name, bench_name + '.c',
>                     dependencies: [qemuutil] + deps)
> diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc
> new file mode 100644
> index 0000000000..6c291b9542
> --- /dev/null
> +++ b/tests/bench/test_akcipher_keys.inc
> @@ -0,0 +1,277 @@
> +/*
> + * 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 <helei.sig11@bytedance.com>
> + */
> +
> +/* 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 96b295263e..4ff2fef30f 100644
> --- a/tests/unit/meson.build
> +++ b/tests/unit/meson.build
> @@ -77,6 +77,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..5efb71f61f
> --- /dev/null
> +++ b/tests/unit/test-crypto-akcipher.c
> @@ -0,0 +1,715 @@

> +
> +typedef struct QCryptoAkcipherTestData QCryptoAkcipherTestData;
> +struct QCryptoAkcipherTestData {
> +    const char *path;
> +    QCryptoAkcipherAlgorithm alg;
> +
> +    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;
> +
> +    union {
> +        QCryptoRsaOptions rsa;
> +        QCryptoEcdsaOptions ecdsa;
> +    } opt;
> +};
> +
> +#define Byte 8
> +static QCryptoAkcipherTestData test_data[] = {
> +    /* rsa1024 with raw padding */
> +    {
> +        .path = "/crypto/akcipher/rsa1024-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 = 1024 / Byte,

I'm not sure this is adding value over just using

   .plen = 128

same for following cases.

> +        .ciphertext = exp_ciphertext_rsa1024_raw,
> +        .clen = sizeof(exp_ciphertext_rsa1024_raw),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
> +            },
> +        }
> +    },
> +
> +    /* rsa1024 with pkcs1 padding */
> +    {
> +        .path = "/crypto/akcipher/rsa1024-pkcs1",
> +        .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 = 1024 / Byte / 2,
> +        .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),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
> +                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
> +            },
> +        }
> +    },
> +
> +    /* rsa2048 with raw padding */
> +    {
> +        .path = "/crypto/akcipher/rsa2048-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 = 2048 / Byte,
> +        .ciphertext = exp_ciphertext_rsa2048_raw,
> +        .clen = sizeof(exp_ciphertext_rsa2048_raw),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
> +            },
> +        }
> +    },
> +
> +    /* rsa2048 with pkcs1 padding */
> +    {
> +        .path = "/crypto/akcipher/rsa2048-pkcs1",
> +        .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 = 2048 / Byte / 2,
> +        .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),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
> +                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
> +            },
> +        }
> +    },
> +
> +};
> +
> +static void test_akcipher(const void *opaque)
> +{
> +    const QCryptoAkcipherTestData *data = opaque;
> +    Error *err = NULL;
> +    uint8_t *plaintext = NULL, *ciphertext = NULL, *signature = NULL;

Declare each of these separately and mark with 'g_autofree'

> +    QCryptoAkcipher *pub_key, *priv_key;
> +
> +    pub_key = qcrypto_akcipher_new(data->alg,
> +                                   QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
> +                                   data->pub_key, data->pub_key_len,
> +                                   (void *)&data->opt, &err);
> +    g_assert(pub_key != NULL);
> +    priv_key = qcrypto_akcipher_new(data->alg,
> +                                    QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
> +                                    data->priv_key, data->priv_key_len,
> +                                    (void *)&data->opt, &err);
> +    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, &err) > 0);
> +        g_assert(err == NULL);
> +
> +        /**
> +         * 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, &err) == data->plen);
> +        g_assert(err == NULL);
> +        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, &err) > 0);
> +        /**
> +         * The signature generated each time may be different, here only check
> +         * the verification.
> +         */
> +        g_assert(err == NULL);
> +
> +        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
> +                                         data->dgst, data->dlen, &err) == 0);
> +        g_assert(err == NULL);
> +        ++signature[0];
> +        /* Here error should be ignored */
> +        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
> +                                         data->dgst, data->dlen, NULL) != 0);
> +    }
> +
> +    g_free(plaintext);
> +    g_free(ciphertext);
> +    g_free(signature);

No need for this with 'g_autofree' at time of declaration.

> +    g_assert(qcrypto_akcipher_free(pub_key, &err) == 0);
> +    g_assert(err == NULL);
> +    g_assert(qcrypto_akcipher_free(priv_key, &err) == 0);
> +    g_assert(err == NULL);

In every call above that passes '&err' you can instead pass
in '&error_abort' and skip the assert.


> +}
> +
> +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);
> +    }

There's no test here that the akcipher APIs are actually implemenmted.
If it runs with a gcrypt build I suspec this test will fail.

I suspect we need an equivalent of 'qcrypto_cipher_supports' and to
query that before registering the test cases.


> +
> +    return g_test_run();
> +}
> -- 
> 2.25.1
> 
> 

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 :|


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 5/6] tests/crypto: Add test suite for crypto akcipher
@ 2022-03-23 15:10     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:10 UTC (permalink / raw)
  To: zhenwei pi; +Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:11AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Add unit test and benchmark test for crypto akcipher.
> 
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  tests/bench/benchmark-crypto-akcipher.c | 163 ++++++
>  tests/bench/meson.build                 |   6 +
>  tests/bench/test_akcipher_keys.inc      | 277 +++++++++
>  tests/unit/meson.build                  |   1 +
>  tests/unit/test-crypto-akcipher.c       | 715 ++++++++++++++++++++++++
>  5 files changed, 1162 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..152fed8d73
> --- /dev/null
> +++ b/tests/bench/benchmark-crypto-akcipher.c
> @@ -0,0 +1,163 @@
> +/*
> + * QEMU Crypto cipher speed benchmark
> + *
> + * Copyright (c) 2022 Bytedance
> + *
> + * Authors:
> + *    lei he <helei.sig11@bytedance.com>
> + *
> + * 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,
> +                                            QCryptoRsaHashAlgorithm hash)
> +{
> +    QCryptoRsaOptions opt;
> +    QCryptoAkcipher *rsa;
> +    Error *err = NULL;
> +
> +    opt.padding_algo = padding;
> +    opt.hash_algo = hash;
> +    rsa = qcrypto_akcipher_new(QCRYPTO_AKCIPHER_ALG_RSA,
> +                               QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
> +                               priv_key, keylen, &opt, &err);
> +
> +    g_assert(rsa != NULL);
> +    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 40
> +#define DURATION_SECONDS 10
> +#define padding QCRYPTO_RSA_PADDING_ALG_PKCS1
> +#define hash QCRYPTO_RSA_HASH_ALG_SHA1

'Byte' 'padding' and 'duration' are 

> +
> +    Error *err = NULL;
> +    QCryptoAkcipher *rsa;
> +    uint8_t *dgst, *signature;
> +    size_t count;
> +
> +    rsa = create_rsa_akcipher(priv_key, keylen, padding, hash);
> +
> +    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),
> +                   QCryptoRsaHashAlgorithm_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, &err) > 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),
> +                   QCryptoRsaHashAlgorithm_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),
> +                   QCryptoRsaHashAlgorithm_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, &err) == 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),
> +                   QCryptoRsaHashAlgorithm_str(hash),
> +                   count, g_test_timer_last(),
> +                   (double)count / g_test_timer_last());
> +
> +    g_assert(qcrypto_akcipher_free(rsa, &err) == 0);
> +    g_free(dgst);
> +    g_free(signature);
> +}
> +
> +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..92491538f9 100644
> --- a/tests/bench/meson.build
> +++ b/tests/bench/meson.build
> @@ -23,6 +23,12 @@ if have_block
>    }
>  endif
>  
> +if nettle.found() and hogweed.found()
> +    benchs += {
> +        'benchmark-crypto-akcipher': [crypto],
> +    }
> +endif
> +
>  foreach bench_name, deps: benchs
>    exe = executable(bench_name, bench_name + '.c',
>                     dependencies: [qemuutil] + deps)
> diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc
> new file mode 100644
> index 0000000000..6c291b9542
> --- /dev/null
> +++ b/tests/bench/test_akcipher_keys.inc
> @@ -0,0 +1,277 @@
> +/*
> + * 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 <helei.sig11@bytedance.com>
> + */
> +
> +/* 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 96b295263e..4ff2fef30f 100644
> --- a/tests/unit/meson.build
> +++ b/tests/unit/meson.build
> @@ -77,6 +77,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..5efb71f61f
> --- /dev/null
> +++ b/tests/unit/test-crypto-akcipher.c
> @@ -0,0 +1,715 @@

> +
> +typedef struct QCryptoAkcipherTestData QCryptoAkcipherTestData;
> +struct QCryptoAkcipherTestData {
> +    const char *path;
> +    QCryptoAkcipherAlgorithm alg;
> +
> +    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;
> +
> +    union {
> +        QCryptoRsaOptions rsa;
> +        QCryptoEcdsaOptions ecdsa;
> +    } opt;
> +};
> +
> +#define Byte 8
> +static QCryptoAkcipherTestData test_data[] = {
> +    /* rsa1024 with raw padding */
> +    {
> +        .path = "/crypto/akcipher/rsa1024-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 = 1024 / Byte,

I'm not sure this is adding value over just using

   .plen = 128

same for following cases.

> +        .ciphertext = exp_ciphertext_rsa1024_raw,
> +        .clen = sizeof(exp_ciphertext_rsa1024_raw),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
> +            },
> +        }
> +    },
> +
> +    /* rsa1024 with pkcs1 padding */
> +    {
> +        .path = "/crypto/akcipher/rsa1024-pkcs1",
> +        .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 = 1024 / Byte / 2,
> +        .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),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
> +                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
> +            },
> +        }
> +    },
> +
> +    /* rsa2048 with raw padding */
> +    {
> +        .path = "/crypto/akcipher/rsa2048-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 = 2048 / Byte,
> +        .ciphertext = exp_ciphertext_rsa2048_raw,
> +        .clen = sizeof(exp_ciphertext_rsa2048_raw),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
> +            },
> +        }
> +    },
> +
> +    /* rsa2048 with pkcs1 padding */
> +    {
> +        .path = "/crypto/akcipher/rsa2048-pkcs1",
> +        .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 = 2048 / Byte / 2,
> +        .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),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
> +                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
> +            },
> +        }
> +    },
> +
> +};
> +
> +static void test_akcipher(const void *opaque)
> +{
> +    const QCryptoAkcipherTestData *data = opaque;
> +    Error *err = NULL;
> +    uint8_t *plaintext = NULL, *ciphertext = NULL, *signature = NULL;

Declare each of these separately and mark with 'g_autofree'

> +    QCryptoAkcipher *pub_key, *priv_key;
> +
> +    pub_key = qcrypto_akcipher_new(data->alg,
> +                                   QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
> +                                   data->pub_key, data->pub_key_len,
> +                                   (void *)&data->opt, &err);
> +    g_assert(pub_key != NULL);
> +    priv_key = qcrypto_akcipher_new(data->alg,
> +                                    QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
> +                                    data->priv_key, data->priv_key_len,
> +                                    (void *)&data->opt, &err);
> +    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, &err) > 0);
> +        g_assert(err == NULL);
> +
> +        /**
> +         * 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, &err) == data->plen);
> +        g_assert(err == NULL);
> +        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, &err) > 0);
> +        /**
> +         * The signature generated each time may be different, here only check
> +         * the verification.
> +         */
> +        g_assert(err == NULL);
> +
> +        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
> +                                         data->dgst, data->dlen, &err) == 0);
> +        g_assert(err == NULL);
> +        ++signature[0];
> +        /* Here error should be ignored */
> +        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
> +                                         data->dgst, data->dlen, NULL) != 0);
> +    }
> +
> +    g_free(plaintext);
> +    g_free(ciphertext);
> +    g_free(signature);

No need for this with 'g_autofree' at time of declaration.

> +    g_assert(qcrypto_akcipher_free(pub_key, &err) == 0);
> +    g_assert(err == NULL);
> +    g_assert(qcrypto_akcipher_free(priv_key, &err) == 0);
> +    g_assert(err == NULL);

In every call above that passes '&err' you can instead pass
in '&error_abort' and skip the assert.


> +}
> +
> +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);
> +    }

There's no test here that the akcipher APIs are actually implemenmted.
If it runs with a gcrypt build I suspec this test will fail.

I suspect we need an equivalent of 'qcrypto_cipher_supports' and to
query that before registering the test cases.


> +
> +    return g_test_run();
> +}
> -- 
> 2.25.1
> 
> 

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 :|


_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 5/6] tests/crypto: Add test suite for crypto akcipher
@ 2022-03-23 15:10     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:10 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, Lei He

On Wed, Mar 23, 2022 at 10:49:11AM +0800, zhenwei pi wrote:
> From: Lei He <helei.sig11@bytedance.com>
> 
> Add unit test and benchmark test for crypto akcipher.
> 
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  tests/bench/benchmark-crypto-akcipher.c | 163 ++++++
>  tests/bench/meson.build                 |   6 +
>  tests/bench/test_akcipher_keys.inc      | 277 +++++++++
>  tests/unit/meson.build                  |   1 +
>  tests/unit/test-crypto-akcipher.c       | 715 ++++++++++++++++++++++++
>  5 files changed, 1162 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..152fed8d73
> --- /dev/null
> +++ b/tests/bench/benchmark-crypto-akcipher.c
> @@ -0,0 +1,163 @@
> +/*
> + * QEMU Crypto cipher speed benchmark
> + *
> + * Copyright (c) 2022 Bytedance
> + *
> + * Authors:
> + *    lei he <helei.sig11@bytedance.com>
> + *
> + * 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,
> +                                            QCryptoRsaHashAlgorithm hash)
> +{
> +    QCryptoRsaOptions opt;
> +    QCryptoAkcipher *rsa;
> +    Error *err = NULL;
> +
> +    opt.padding_algo = padding;
> +    opt.hash_algo = hash;
> +    rsa = qcrypto_akcipher_new(QCRYPTO_AKCIPHER_ALG_RSA,
> +                               QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
> +                               priv_key, keylen, &opt, &err);
> +
> +    g_assert(rsa != NULL);
> +    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 40
> +#define DURATION_SECONDS 10
> +#define padding QCRYPTO_RSA_PADDING_ALG_PKCS1
> +#define hash QCRYPTO_RSA_HASH_ALG_SHA1

'Byte' 'padding' and 'duration' are 

> +
> +    Error *err = NULL;
> +    QCryptoAkcipher *rsa;
> +    uint8_t *dgst, *signature;
> +    size_t count;
> +
> +    rsa = create_rsa_akcipher(priv_key, keylen, padding, hash);
> +
> +    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),
> +                   QCryptoRsaHashAlgorithm_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, &err) > 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),
> +                   QCryptoRsaHashAlgorithm_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),
> +                   QCryptoRsaHashAlgorithm_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, &err) == 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),
> +                   QCryptoRsaHashAlgorithm_str(hash),
> +                   count, g_test_timer_last(),
> +                   (double)count / g_test_timer_last());
> +
> +    g_assert(qcrypto_akcipher_free(rsa, &err) == 0);
> +    g_free(dgst);
> +    g_free(signature);
> +}
> +
> +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..92491538f9 100644
> --- a/tests/bench/meson.build
> +++ b/tests/bench/meson.build
> @@ -23,6 +23,12 @@ if have_block
>    }
>  endif
>  
> +if nettle.found() and hogweed.found()
> +    benchs += {
> +        'benchmark-crypto-akcipher': [crypto],
> +    }
> +endif
> +
>  foreach bench_name, deps: benchs
>    exe = executable(bench_name, bench_name + '.c',
>                     dependencies: [qemuutil] + deps)
> diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.inc
> new file mode 100644
> index 0000000000..6c291b9542
> --- /dev/null
> +++ b/tests/bench/test_akcipher_keys.inc
> @@ -0,0 +1,277 @@
> +/*
> + * 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 <helei.sig11@bytedance.com>
> + */
> +
> +/* 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 96b295263e..4ff2fef30f 100644
> --- a/tests/unit/meson.build
> +++ b/tests/unit/meson.build
> @@ -77,6 +77,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..5efb71f61f
> --- /dev/null
> +++ b/tests/unit/test-crypto-akcipher.c
> @@ -0,0 +1,715 @@

> +
> +typedef struct QCryptoAkcipherTestData QCryptoAkcipherTestData;
> +struct QCryptoAkcipherTestData {
> +    const char *path;
> +    QCryptoAkcipherAlgorithm alg;
> +
> +    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;
> +
> +    union {
> +        QCryptoRsaOptions rsa;
> +        QCryptoEcdsaOptions ecdsa;
> +    } opt;
> +};
> +
> +#define Byte 8
> +static QCryptoAkcipherTestData test_data[] = {
> +    /* rsa1024 with raw padding */
> +    {
> +        .path = "/crypto/akcipher/rsa1024-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 = 1024 / Byte,

I'm not sure this is adding value over just using

   .plen = 128

same for following cases.

> +        .ciphertext = exp_ciphertext_rsa1024_raw,
> +        .clen = sizeof(exp_ciphertext_rsa1024_raw),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
> +            },
> +        }
> +    },
> +
> +    /* rsa1024 with pkcs1 padding */
> +    {
> +        .path = "/crypto/akcipher/rsa1024-pkcs1",
> +        .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 = 1024 / Byte / 2,
> +        .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),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
> +                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
> +            },
> +        }
> +    },
> +
> +    /* rsa2048 with raw padding */
> +    {
> +        .path = "/crypto/akcipher/rsa2048-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 = 2048 / Byte,
> +        .ciphertext = exp_ciphertext_rsa2048_raw,
> +        .clen = sizeof(exp_ciphertext_rsa2048_raw),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW,
> +            },
> +        }
> +    },
> +
> +    /* rsa2048 with pkcs1 padding */
> +    {
> +        .path = "/crypto/akcipher/rsa2048-pkcs1",
> +        .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 = 2048 / Byte / 2,
> +        .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),
> +
> +        .opt = {
> +            .rsa = {
> +                .padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1,
> +                .hash_algo = QCRYPTO_RSA_HASH_ALG_SHA1,
> +            },
> +        }
> +    },
> +
> +};
> +
> +static void test_akcipher(const void *opaque)
> +{
> +    const QCryptoAkcipherTestData *data = opaque;
> +    Error *err = NULL;
> +    uint8_t *plaintext = NULL, *ciphertext = NULL, *signature = NULL;

Declare each of these separately and mark with 'g_autofree'

> +    QCryptoAkcipher *pub_key, *priv_key;
> +
> +    pub_key = qcrypto_akcipher_new(data->alg,
> +                                   QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
> +                                   data->pub_key, data->pub_key_len,
> +                                   (void *)&data->opt, &err);
> +    g_assert(pub_key != NULL);
> +    priv_key = qcrypto_akcipher_new(data->alg,
> +                                    QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
> +                                    data->priv_key, data->priv_key_len,
> +                                    (void *)&data->opt, &err);
> +    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, &err) > 0);
> +        g_assert(err == NULL);
> +
> +        /**
> +         * 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, &err) == data->plen);
> +        g_assert(err == NULL);
> +        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, &err) > 0);
> +        /**
> +         * The signature generated each time may be different, here only check
> +         * the verification.
> +         */
> +        g_assert(err == NULL);
> +
> +        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
> +                                         data->dgst, data->dlen, &err) == 0);
> +        g_assert(err == NULL);
> +        ++signature[0];
> +        /* Here error should be ignored */
> +        g_assert(qcrypto_akcipher_verify(pub_key, signature, data->slen,
> +                                         data->dgst, data->dlen, NULL) != 0);
> +    }
> +
> +    g_free(plaintext);
> +    g_free(ciphertext);
> +    g_free(signature);

No need for this with 'g_autofree' at time of declaration.

> +    g_assert(qcrypto_akcipher_free(pub_key, &err) == 0);
> +    g_assert(err == NULL);
> +    g_assert(qcrypto_akcipher_free(priv_key, &err) == 0);
> +    g_assert(err == NULL);

In every call above that passes '&err' you can instead pass
in '&error_abort' and skip the assert.


> +}
> +
> +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);
> +    }

There's no test here that the akcipher APIs are actually implemenmted.
If it runs with a gcrypt build I suspec this test will fail.

I suspect we need an equivalent of 'qcrypto_cipher_supports' and to
query that before registering the test cases.


> +
> +    return g_test_run();
> +}
> -- 
> 2.25.1
> 
> 

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 :|



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 1/6] virtio-crypto: header update
  2022-03-23  2:49   ` zhenwei pi
  (?)
@ 2022-03-23 15:38     ` Daniel P. Berrangé
  -1 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:38 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, herbert, jasowang, qemu-devel, virtualization,
	linux-crypto, lei he

On Wed, Mar 23, 2022 at 10:49:07AM +0800, zhenwei pi wrote:
> Update header from linux, support akcipher service.

I'm assuming this is updated for *non-merged* Linux headers, since
I don't see these changes present in current linux.git 

> 
> Reviewed-by: Gonglei <arei.gonglei@huawei.com>
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  .../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

Do we really need to be adding support for all these obsolete
hash functions. Maybe SHA1 is borderline acceptable, but all
those obsolete MD* functions too ??

> +#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

Here we have RSA, DSA and ECDSA, but the corresponding QEMU
qapi/crypto.json doesn't define DSA at all. Is that a mistake
on the QEMU side, or is the DSA support redundant ?

> +	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;
> +};


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 :|


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 1/6] virtio-crypto: header update
@ 2022-03-23 15:38     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:38 UTC (permalink / raw)
  To: zhenwei pi; +Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, lei he

On Wed, Mar 23, 2022 at 10:49:07AM +0800, zhenwei pi wrote:
> Update header from linux, support akcipher service.

I'm assuming this is updated for *non-merged* Linux headers, since
I don't see these changes present in current linux.git 

> 
> Reviewed-by: Gonglei <arei.gonglei@huawei.com>
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  .../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

Do we really need to be adding support for all these obsolete
hash functions. Maybe SHA1 is borderline acceptable, but all
those obsolete MD* functions too ??

> +#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

Here we have RSA, DSA and ECDSA, but the corresponding QEMU
qapi/crypto.json doesn't define DSA at all. Is that a mistake
on the QEMU side, or is the DSA support redundant ?

> +	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;
> +};


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 :|

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [PATCH v3 1/6] virtio-crypto: header update
@ 2022-03-23 15:38     ` Daniel P. Berrangé
  0 siblings, 0 replies; 62+ messages in thread
From: Daniel P. Berrangé @ 2022-03-23 15:38 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, lei he

On Wed, Mar 23, 2022 at 10:49:07AM +0800, zhenwei pi wrote:
> Update header from linux, support akcipher service.

I'm assuming this is updated for *non-merged* Linux headers, since
I don't see these changes present in current linux.git 

> 
> Reviewed-by: Gonglei <arei.gonglei@huawei.com>
> Signed-off-by: lei he <helei.sig11@bytedance.com>
> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
> ---
>  .../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

Do we really need to be adding support for all these obsolete
hash functions. Maybe SHA1 is borderline acceptable, but all
those obsolete MD* functions too ??

> +#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

Here we have RSA, DSA and ECDSA, but the corresponding QEMU
qapi/crypto.json doesn't define DSA at all. Is that a mistake
on the QEMU side, or is the DSA support redundant ?

> +	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;
> +};


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 :|



^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 1/6] virtio-crypto: header update
  2022-03-23 15:38     ` Daniel P. Berrangé
  (?)
@ 2022-03-23 15:59       ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23 15:59 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: arei.gonglei, mst, herbert, jasowang, qemu-devel, virtualization,
	linux-crypto, lei he

On 3/23/22 23:38, Daniel P. Berrangé wrote:
> On Wed, Mar 23, 2022 at 10:49:07AM +0800, zhenwei pi wrote:
>> Update header from linux, support akcipher service.
> 
> I'm assuming this is updated for *non-merged* Linux headers, since
> I don't see these changes present in current linux.git
> 
>>
Hi,

The related context link:
https://lkml.org/lkml/2022/3/1/1425

- The virtio crypto spec is the first part. It will be deferred to 1.3.
The latest version: 
https://www.oasis-open.org/committees/ballot.php?id=3681 (need put 
"__le32 akcipher_algo;" instead of "__le32 reserve;" and repost)

- According to the spec, then we can define the linux headers. (depend 
on the spec)

- Update the header file for QEMU. (depend on the linux headers)

All the parts are in development.

-- 
zhenwei pi

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 1/6] virtio-crypto: header update
@ 2022-03-23 15:59       ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23 15:59 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, lei he

On 3/23/22 23:38, Daniel P. Berrangé wrote:
> On Wed, Mar 23, 2022 at 10:49:07AM +0800, zhenwei pi wrote:
>> Update header from linux, support akcipher service.
> 
> I'm assuming this is updated for *non-merged* Linux headers, since
> I don't see these changes present in current linux.git
> 
>>
Hi,

The related context link:
https://lkml.org/lkml/2022/3/1/1425

- The virtio crypto spec is the first part. It will be deferred to 1.3.
The latest version: 
https://www.oasis-open.org/committees/ballot.php?id=3681 (need put 
"__le32 akcipher_algo;" instead of "__le32 reserve;" and repost)

- According to the spec, then we can define the linux headers. (depend 
on the spec)

- Update the header file for QEMU. (depend on the linux headers)

All the parts are in development.

-- 
zhenwei pi
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 1/6] virtio-crypto: header update
@ 2022-03-23 15:59       ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-23 15:59 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, lei he

On 3/23/22 23:38, Daniel P. Berrangé wrote:
> On Wed, Mar 23, 2022 at 10:49:07AM +0800, zhenwei pi wrote:
>> Update header from linux, support akcipher service.
> 
> I'm assuming this is updated for *non-merged* Linux headers, since
> I don't see these changes present in current linux.git
> 
>>
Hi,

The related context link:
https://lkml.org/lkml/2022/3/1/1425

- The virtio crypto spec is the first part. It will be deferred to 1.3.
The latest version: 
https://www.oasis-open.org/committees/ballot.php?id=3681 (need put 
"__le32 akcipher_algo;" instead of "__le32 reserve;" and repost)

- According to the spec, then we can define the linux headers. (depend 
on the spec)

- Update the header file for QEMU. (depend on the linux headers)

All the parts are in development.

-- 
zhenwei pi


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
  2022-03-23  7:32     ` zhenwei pi
@ 2022-03-23 18:03       ` Eric Biggers
  -1 siblings, 0 replies; 62+ messages in thread
From: Eric Biggers @ 2022-03-23 18:03 UTC (permalink / raw)
  To: zhenwei pi
  Cc: arei.gonglei, mst, jasowang, virtualization, qemu-devel,
	linux-crypto, herbert, helei.sig11

On Wed, Mar 23, 2022 at 03:32:37PM +0800, zhenwei pi wrote:
> 
> On 3/23/22 13:17, Eric Biggers wrote:
> > On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> > > 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 (3):
> > >    crypto-akcipher: Introduce akcipher types to qapi
> > >    crypto: Implement RSA algorithm by hogweed
> > >    tests/crypto: Add test suite for crypto akcipher
> > > 
> > > Zhenwei Pi (3):
> > >    virtio-crypto: header update
> > >    crypto: Introduce akcipher crypto class
> > >    virtio-crypto: Introduce RSA algorithm
> > 
> > You forgot to describe the point of this patchset and what its use case is.
> > Like any other Linux kernel patchset, that needs to be in the cover letter.
> > 
> > - Eric
> Thanks Eric for pointing this missing part.
> 
> This feature provides akcipher service offloading capability. QEMU side
> handles asymmetric requests via virtio-crypto devices from guest side, do
> encrypt/decrypt/sign/verify operations on host side, and return the result
> to guest.
> 
> This patchset implements a RSA backend by hogweed from nettle, it works
> together with guest patch:
> https://lkml.org/lkml/2022/3/1/1425

So what is the use case?

- Eric

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-23 18:03       ` Eric Biggers
  0 siblings, 0 replies; 62+ messages in thread
From: Eric Biggers @ 2022-03-23 18:03 UTC (permalink / raw)
  To: zhenwei pi
  Cc: herbert, mst, jasowang, qemu-devel, virtualization, arei.gonglei,
	linux-crypto, helei.sig11

On Wed, Mar 23, 2022 at 03:32:37PM +0800, zhenwei pi wrote:
> 
> On 3/23/22 13:17, Eric Biggers wrote:
> > On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> > > 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 (3):
> > >    crypto-akcipher: Introduce akcipher types to qapi
> > >    crypto: Implement RSA algorithm by hogweed
> > >    tests/crypto: Add test suite for crypto akcipher
> > > 
> > > Zhenwei Pi (3):
> > >    virtio-crypto: header update
> > >    crypto: Introduce akcipher crypto class
> > >    virtio-crypto: Introduce RSA algorithm
> > 
> > You forgot to describe the point of this patchset and what its use case is.
> > Like any other Linux kernel patchset, that needs to be in the cover letter.
> > 
> > - Eric
> Thanks Eric for pointing this missing part.
> 
> This feature provides akcipher service offloading capability. QEMU side
> handles asymmetric requests via virtio-crypto devices from guest side, do
> encrypt/decrypt/sign/verify operations on host side, and return the result
> to guest.
> 
> This patchset implements a RSA backend by hogweed from nettle, it works
> together with guest patch:
> https://lkml.org/lkml/2022/3/1/1425

So what is the use case?

- Eric


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
  2022-03-23 18:03       ` Eric Biggers
  (?)
@ 2022-03-24  1:20         ` zhenwei pi
  -1 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-24  1:20 UTC (permalink / raw)
  To: Eric Biggers, Daniel P. Berrangé
  Cc: arei.gonglei, mst, jasowang, virtualization, qemu-devel,
	linux-crypto, herbert, helei.sig11, Zeng, Xin

On 3/24/22 02:03, Eric Biggers wrote:
> On Wed, Mar 23, 2022 at 03:32:37PM +0800, zhenwei pi wrote:
>>
>> On 3/23/22 13:17, Eric Biggers wrote:
>>> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>>>> 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 (3):
>>>>     crypto-akcipher: Introduce akcipher types to qapi
>>>>     crypto: Implement RSA algorithm by hogweed
>>>>     tests/crypto: Add test suite for crypto akcipher
>>>>
>>>> Zhenwei Pi (3):
>>>>     virtio-crypto: header update
>>>>     crypto: Introduce akcipher crypto class
>>>>     virtio-crypto: Introduce RSA algorithm
>>>
>>> You forgot to describe the point of this patchset and what its use case is.
>>> Like any other Linux kernel patchset, that needs to be in the cover letter.
>>>
>>> - Eric
>> Thanks Eric for pointing this missing part.
>>
>> This feature provides akcipher service offloading capability. QEMU side
>> handles asymmetric requests via virtio-crypto devices from guest side, do
>> encrypt/decrypt/sign/verify operations on host side, and return the result
>> to guest.
>>
>> This patchset implements a RSA backend by hogweed from nettle, it works
>> together with guest patch:
>> https://lkml.org/lkml/2022/3/1/1425
> 
> So what is the use case?
> 
> - Eric
Hi,

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 <helei.sig11@bytedance.com>
	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.

-- 
zhenwei pi

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-24  1:20         ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-24  1:20 UTC (permalink / raw)
  To: Eric Biggers, Daniel P. Berrangé
  Cc: herbert, mst, qemu-devel, virtualization, linux-crypto, helei.sig11

On 3/24/22 02:03, Eric Biggers wrote:
> On Wed, Mar 23, 2022 at 03:32:37PM +0800, zhenwei pi wrote:
>>
>> On 3/23/22 13:17, Eric Biggers wrote:
>>> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>>>> 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 (3):
>>>>     crypto-akcipher: Introduce akcipher types to qapi
>>>>     crypto: Implement RSA algorithm by hogweed
>>>>     tests/crypto: Add test suite for crypto akcipher
>>>>
>>>> Zhenwei Pi (3):
>>>>     virtio-crypto: header update
>>>>     crypto: Introduce akcipher crypto class
>>>>     virtio-crypto: Introduce RSA algorithm
>>>
>>> You forgot to describe the point of this patchset and what its use case is.
>>> Like any other Linux kernel patchset, that needs to be in the cover letter.
>>>
>>> - Eric
>> Thanks Eric for pointing this missing part.
>>
>> This feature provides akcipher service offloading capability. QEMU side
>> handles asymmetric requests via virtio-crypto devices from guest side, do
>> encrypt/decrypt/sign/verify operations on host side, and return the result
>> to guest.
>>
>> This patchset implements a RSA backend by hogweed from nettle, it works
>> together with guest patch:
>> https://lkml.org/lkml/2022/3/1/1425
> 
> So what is the use case?
> 
> - Eric
Hi,

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 <helei.sig11@bytedance.com>
	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.

-- 
zhenwei pi
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto
@ 2022-03-24  1:20         ` zhenwei pi
  0 siblings, 0 replies; 62+ messages in thread
From: zhenwei pi @ 2022-03-24  1:20 UTC (permalink / raw)
  To: Eric Biggers, Daniel P. Berrangé
  Cc: herbert, mst, jasowang, Zeng, Xin, qemu-devel, virtualization,
	arei.gonglei, linux-crypto, helei.sig11

On 3/24/22 02:03, Eric Biggers wrote:
> On Wed, Mar 23, 2022 at 03:32:37PM +0800, zhenwei pi wrote:
>>
>> On 3/23/22 13:17, Eric Biggers wrote:
>>> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>>>> 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 (3):
>>>>     crypto-akcipher: Introduce akcipher types to qapi
>>>>     crypto: Implement RSA algorithm by hogweed
>>>>     tests/crypto: Add test suite for crypto akcipher
>>>>
>>>> Zhenwei Pi (3):
>>>>     virtio-crypto: header update
>>>>     crypto: Introduce akcipher crypto class
>>>>     virtio-crypto: Introduce RSA algorithm
>>>
>>> You forgot to describe the point of this patchset and what its use case is.
>>> Like any other Linux kernel patchset, that needs to be in the cover letter.
>>>
>>> - Eric
>> Thanks Eric for pointing this missing part.
>>
>> This feature provides akcipher service offloading capability. QEMU side
>> handles asymmetric requests via virtio-crypto devices from guest side, do
>> encrypt/decrypt/sign/verify operations on host side, and return the result
>> to guest.
>>
>> This patchset implements a RSA backend by hogweed from nettle, it works
>> together with guest patch:
>> https://lkml.org/lkml/2022/3/1/1425
> 
> So what is the use case?
> 
> - Eric
Hi,

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 <helei.sig11@bytedance.com>
	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.

-- 
zhenwei pi


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [External] [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
  2022-03-23 13:50     ` Daniel P. Berrangé
@ 2022-03-28  9:14       ` 何磊
  -1 siblings, 0 replies; 62+ messages in thread
From: 何磊 @ 2022-03-28  9:14 UTC (permalink / raw)
  To: "Daniel P. Berrangé"
  Cc: 何磊,
	zhenwei pi, arei.gonglei, Michael S. Tsirkin, herbert, jasowang,
	qemu-devel, virtualization, linux-crypto



> On Mar 23, 2022, at 9:50 PM, Daniel P. Berrangé <berrange@redhat.com> wrote:
> 
> On Wed, Mar 23, 2022 at 10:49:10AM +0800, zhenwei pi wrote:
>> From: Lei He <helei.sig11@bytedance.com>
>> 
>> Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
>> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
>> ---
>> crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
>> crypto/akcipher.c         |   3 +
>> crypto/asn1_decoder.c     | 185 ++++++++++++++
>> crypto/asn1_decoder.h     |  42 +++
> 
> Please introduce the asn1 files in a separate commit, and also
> provide a unit test to validate them in the same commit.
> 
>> diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
>> new file mode 100644
>> index 0000000000..45b93af772
>> --- /dev/null
>> +++ b/crypto/akcipher-nettle.c
>> @@ -0,0 +1,523 @@
>> +/*
>> + * QEMU Crypto akcipher algorithms
>> + *
>> + * Copyright (c) 2022 Bytedance
>> + * Author: lei he <helei.sig11@bytedance.com>
>> + *
>> + * 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 <stdbool.h>
>> +
>> +#include <nettle/rsa.h>
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu/host-utils.h"
>> +#include "asn1_decoder.h"
>> +#include "crypto/akcipher.h"
>> +#include "crypto/random.h"
>> +#include "qapi/error.h"
>> +#include "sysemu/cryptodev.h"
>> +
>> +typedef struct QCryptoNettleRsa {
>> +    QCryptoAkcipher akcipher;
>> +    struct rsa_public_key pub;
>> +    struct rsa_private_key priv;
>> +    QCryptoRsaPaddingAlgorithm padding_algo;
>> +    QCryptoRsaHashAlgorithm hash_algo;
>> +} QCryptoNettleRsa;
> 
> Call this QCryptoAkCipherNettleRSA
> 
>> +
>> +struct asn1_parse_ctx {
>> +    const uint8_t *data;
>> +    size_t dlen;
>> +};
>> +
>> +#define Octet 8
>> +
>> +static int extract_value(void *p, const uint8_t *data, size_t dlen)
>> +{
>> +    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
>> +    ctx->data = (uint8_t *)data;
>> +    ctx->dlen = dlen;
>> +
>> +    return 0;
>> +}
>> +
>> +static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
>> +{
>> +    mpz_t *target = (mpz_t *)p;
>> +    nettle_mpz_set_str_256_u(*target, dlen, data);
>> +
>> +    return 0;
>> +}
>> +
>> +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
>> +
>> +static void qcrypto_nettle_rsa_destroy(void *ptr)
>> +{
>> +    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
>> +    if (!rsa) {
>> +        return;
>> +    }
>> +
>> +    rsa_public_key_clear(&rsa->pub);
>> +    rsa_private_key_clear(&rsa->priv);
>> +    g_free(rsa);
>> +}
>> +
>> +static QCryptoAkcipher *qcrypto_nettle_new_rsa(
>> +    QCryptoAkcipherKeyType type,
>> +    const uint8_t *key,  size_t keylen,
>> +    QCryptoRsaOptions *opt, Error **errp);
>> +
>> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
>> +                                             QCryptoAkcipherKeyType type,
>> +                                             const uint8_t *key,
>> +                                             size_t keylen, void *para,
>> +                                             Error **errp)
>> +{
>> +    switch (alg) {
>> +    case QCRYPTO_AKCIPHER_ALG_RSA:
>> +        return qcrypto_nettle_new_rsa(type, key, keylen,
>> +                                      (QCryptoRsaOptions *)para, errp);
>> +    default:
>> +        error_setg(errp, "Unsupported algorithm: %u", alg);
>> +        return NULL;
>> +    }
>> +
>> +    return NULL;
>> +}
>> +
>> +/**
>> + * Parse ber encoded rsa private key, asn1 schema:
>> + *        RsaPrivKey ::= SEQUENCE {
>> + *             version     INTEGER
>> + *             n           INTEGER
>> + *             e           INTEGER
>> + *             d           INTEGER
>> + *             p           INTEGER
>> + *             q           INTEGER
>> + *             e1          INTEGER
>> + *             e2          INTEGER
>> + *             u           INTEGER
>> + *         }
>> + */
>> +static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
>> +                                 const uint8_t *key, size_t keylen)
>> +{
>> +    struct asn1_parse_ctx ctx;
>> +
>> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
>> +        keylen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
>> +        ctx.dlen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (!rsa_public_key_prepare(&rsa->pub)) {
>> +        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
>> +     */
>> +    rsa->priv.size = rsa->pub.size;
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>> + * Parse ber encoded rsa pubkey, asn1 schema:
>> + *        RsaPrivKey ::= SEQUENCE {
>> + *             n           INTEGER
>> + *             e           INTEGER
>> + *         }
>> + */
>> +static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
>> +                                const uint8_t *key,
>> +                                size_t keylen)
>> +{
>> +    struct asn1_parse_ctx ctx;
>> +
>> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
>> +        keylen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
>> +        ctx.dlen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (!rsa_public_key_prepare(&rsa->pub)) {
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
> 
> I'd like to see these APIs for parsing RSA keys split out into
> a separate file, crypto/rsakey.{c,h}.  Define a struct to hold
> the RSA key parameters so it isn't tied to nettle, allowing
> its potential reuse with a gcrypt/gnutls impl of these APIs

So we should define the following structures to avoid tieing to nettle?

struct QCryptoRSAParameter {
	uint8_t *data;
       size_t data_len;
};

struct QCryptoRSAKey {
	QCryptoRSAParameter n;
	QCryptoRSAParameter e;
	QCryptoRSAParameter d;
	QCryptoRSAParameter p;
	QCryptoRSAParameter q;
       ...
};

> 
>> +
>> +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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
>> +    QCryptoAkcipherKeyType type,
>> +    const uint8_t *key, size_t keylen,
>> +    QCryptoRsaOptions *opt, Error **errp)
>> +{
>> +    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
>> +    rsa->padding_algo = opt->padding_algo;
>> +    rsa->hash_algo = opt->hash_algo;
>> +
>> +    switch (type) {
>> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
>> +        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
>> +            qcrypto_nettle_rsa_set_akcipher_size(
>> +                (QCryptoAkcipher *)rsa, rsa->priv.size);
>> +            return (QCryptoAkcipher *)rsa;
>> +        }
>> +        error_setg(errp, "Failed to parse rsa private key");
> 
> This code pattern is back to front of what we would normally
> do.  ie I'd expect it to look like this:
> 
>         if (parse_rsa_private_key(rsa, key, keylen) != 0) {
>             error_setg(errp, "Failed to parse rsa private key");
> 	     goto error;
>         }
> 
>         qcrypto_nettle_rsa_set_akcipher_size(
>                 (QCryptoAkcipher *)rsa, rsa->priv.size);
>         return (QCryptoAkcipher *)rsa;
> 
> 
> 
>> +        break;
>> +
>> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
>> +        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
>> +            qcrypto_nettle_rsa_set_akcipher_size(
>> +                (QCryptoAkcipher *)rsa, rsa->pub.size);
>> +            return (QCryptoAkcipher *)rsa;
>> +        }
>> +        error_setg(errp, "Failed to parse rsa public rsa key");
>> +        break;
>> +
>> +    default:
>> +        error_setg(errp, "Unknown akcipher key type %d", type);
>> +    }
>> +
>> +    qcrypto_nettle_rsa_destroy(rsa);
>> +    return NULL;
>> +}
>> +
>> +
>> +/**
>> + * nettle does not provide RSA interfaces without padding,
>> + * here we implemented rsa algorithm with nettle/mpz.
>> + */
> 
> Urgh, this is really unpleasant. I don't want to see QEMU
> implementing any further crypto algorithms directly, only
> ever consume and wrap impls from external libraries. We've
> got a few in QEMU for historical reasons, but don't want
> to add more. There are too many ways to mess up crypto
> opening the door to subtle timing / side channel attacks,
> and crypto impls also cause distributors pain with export
> compliance rules.
> 
> If nettle doesn't provide an impl without padding, then
> simply don't implement it. Report an error if the caller
> tries to enable it.
> 
> An alternate gcrypt impl of these APIs might allow for
> an impl without padding.
> 
>> +static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
>> +                        size_t data_len, void *enc,
>> +                        size_t enc_len, Error **errp)
>> +{
>> +    mpz_t m;
>> +    int ret;
>> +
>> +    nettle_mpz_init_set_str_256_u(m, data_len, data);
>> +    /* (1) Validate 0 <= m < n */
>> +    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
>> +        error_setg(errp, "Failed to validate input data");
>> +        return -1;
>> +    }
>> +
>> +    /* (2) c = m ^ e mod n */
>> +    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
>> +    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
>> +        ret = -1;
>> +    } else {
>> +        ret = enc_len;
>> +        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
>> +    }
>> +
>> +    mpz_clear(m);
>> +
>> +    return ret;
>> +}
>> +
>> +static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
>> +                        const void *enc,
>> +                        size_t enc_len,
>> +                        void *data,
>> +                        size_t data_len,
>> +                        Error **errp)
>> +{
>> +    mpz_t c;
>> +    int ret;
>> +    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
>> +
>> +    /* (1) Validate 0 <= c < n */
>> +    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
>> +        error_setg(errp, "Failed to validate input data");
>> +        return -1;
>> +    }
>> +
>> +    /* (2) m = c ^ d mod n */
>> +    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
>> +    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
>> +        ret = -1;
>> +    } else {
>> +        ret = data_len;
>> +        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
>> +    }
>> +
>> +    mpz_clear(c);
>> +
>> +    return ret;
>> +}
>> +
>> +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
>> +{
>> +    /* TODO: check result */
>> +    qcrypto_random_bytes(out, len, NULL);
>> +}
>> +
>> +static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
>> +                                      const void *data, size_t data_len,
>> +                                      void *enc, size_t enc_len,
>> +                                      Error **errp)
>> +{
>> +
>> +    QCryptoNettleRsa *rsa =
>> +        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
>> +    mpz_t c;
>> +    int enc_ret;
>> +
>> +    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    switch (rsa->padding_algo) {
>> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
>> +        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
>> +
>> +    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
>> +        mpz_init(c);
>> +        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
>> +                              data_len, (uint8_t *)data, c);
>> +        if (enc_ret != 1) {
>> +            error_setg(errp, "Failed to encrypt");
>> +            enc_ret = -1;
>> +        } else {
>> +            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
>> +            enc_ret = enc_len;
>> +        }
>> +        mpz_clear(c);
>> +        return enc_ret;
>> +
>> +    default:
>> +        error_setg(errp, "Unknown padding");
>> +        return -1;
>> +    }
>> +
>> +    return -1;
>> +}
>> +
>> +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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
>> +    mpz_t c;
>> +    int ret;
>> +    if (enc_len > rsa->priv.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    switch (rsa->padding_algo) {
>> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
>> +        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
>> +        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");
>> +            ret = -1;
>> +        } else {
>> +            ret = data_len;
>> +        }
>> +
>> +        mpz_clear(c);
>> +        break;
>> +
>> +    default:
>> +        ret = -1;
>> +        error_setg(errp, "Unknown padding");
>> +    }
>> +
>> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
>> +    int ret;
>> +    mpz_t s;
>> +
>> +    /**
>> +     * The RSA algorithm cannot be used for signature/verification
>> +     * without padding.
>> +     */
>> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
>> +        error_setg(errp, "Try to make signature without padding");
>> +        return -1;
>> +    }
>> +
>> +    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    mpz_init(s);
>> +    switch (rsa->hash_algo) {
>> +    case QCRYPTO_RSA_HASH_ALG_MD5:
>> +        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
>> +        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
>> +        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
>> +        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    default:
>> +        error_setg(errp, "Unknown hash algorithm");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +
>> +    if (ret != 1) {
>> +        error_setg(errp, "Failed to make signature");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
>> +    ret = sig_len;
>> +
>> +clear:
>> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
>> +
>> +    int ret;
>> +    mpz_t s;
>> +
>> +    /**
>> +     * The RSA algorithm cannot be used for signature/verification
>> +     * without padding.
>> +     */
>> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
>> +        error_setg(errp, "Operation not supported");
>> +        return -1;
>> +    }
>> +    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
>> +    switch (rsa->hash_algo) {
>> +    case QCRYPTO_RSA_HASH_ALG_MD5:
>> +        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
>> +        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
>> +        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
>> +        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    default:
>> +        error_setg(errp, "Unsupported hash algorithm");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +
>> +    if (ret != 1) {
>> +        error_setg(errp, "Failed to verify");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +    ret = 0;
>> +
>> +clear:
>> +    mpz_clear(s);
>> +
>> +    return ret;
>> +}
>> +
>> +static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
>> +                                   Error **errp)
>> +{
>> +    qcrypto_nettle_rsa_destroy(akcipher);
>> +    return 0;
>> +}
>> +
>> +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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
>> +{
>> +    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));
> 
> s/g_mallo0/g_new0/
> 
>> +    memset(rsa, 0, sizeof(QCryptoNettleRsa));
> 
> It is already initialized to zero by the allocator above.
> 
>> +    rsa->akcipher.driver = &nettle_rsa;
>> +    rsa_public_key_init(&rsa->pub);
>> +    rsa_private_key_init(&rsa->priv);
> 
> I don't think this method should exist at all though. It only
> has one caller, so just put the code inline there.
> 
>> +
>> +    return rsa;
>> +}
>> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
>> index 1e52f2fd76..b5c04e8424 100644
>> --- a/crypto/akcipher.c
>> +++ b/crypto/akcipher.c
>> @@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
>> {
>>     QCryptoAkcipher *akcipher = NULL;
>> 
>> +    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
>> +                                           para, errp);
>> +
>>     return akcipher;
>> }
> 
> Hard-wiring this to use the nettle impl is not at all desirable. It
> needs to use a pluggable approach, with a strong preferance to match
> the design of the crypto/cipher.c
> 
>> 
>> diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
>> new file mode 100644
>> index 0000000000..bfb145e84e
>> --- /dev/null
>> +++ b/crypto/asn1_decoder.c
>> @@ -0,0 +1,185 @@
>> +/*
>> + * QEMU Crypto akcipher algorithms
> 
> This comment is wrong
> 
>> + *
>> + * Copyright (c) 2022 Bytedance
>> + * Author: lei he <helei.sig11@bytedance.com>
>> + *
>> + * 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 <stdint.h>
>> +#include <stddef.h>
>> +
>> +#include "crypto/asn1_decoder.h"
>> +
>> +enum ber_type_tag {
>> +    ber_type_tag_bool = 0x1,
>> +    ber_type_tag_int = 0x2,
>> +    ber_type_tag_bit_str = 0x3,
>> +    ber_type_tag_oct_str = 0x4,
>> +    ber_type_tag_oct_null = 0x5,
>> +    ber_type_tag_oct_oid = 0x6,
>> +    ber_type_tag_seq = 0x10,
>> +    ber_type_tag_set = 0x11,
>> +};
>> +
>> +#define BER_CONSTRUCTED_MASK 0x20
>> +#define BER_SHORT_LEN_MASK 0x80
>> +
>> +static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
>> +{
>> +    return **data;
>> +}
>> +
>> +static int invoke_callback(BerDecodeCb cb, void *ctx,
>> +                           const uint8_t *value, size_t vlen)
>> +{
>> +    if (!cb) {
>> +        return 0;
>> +    }
>> +
>> +    return cb(ctx, value, vlen);
>> +}
>> +
>> +static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
>> +                           size_t nbytes)
>> +{
>> +    *data += nbytes;
>> +    *dlen -= nbytes;
>> +}
>> +
>> +static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
>> +{
>> +    uint8_t val = ber_peek_byte(data, dlen);
>> +
>> +    ber_cut_nbytes(data, dlen, 1);
>> +
>> +    return val;
>> +}
>> +
>> +static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
>> +                                     BerDecodeCb cb, void *ctx)
>> +{
>> +    const uint8_t *value;
>> +    size_t vlen = 0;
>> +    uint8_t byte_count = ber_cut_byte(data, dlen);
>> +
>> +    /* short format of definite-length */
>> +    if (!(byte_count & BER_SHORT_LEN_MASK)) {
>> +        if (byte_count > *dlen) {
>> +            return -1;
>> +        }
>> +
>> +        value = *data;
>> +        vlen = byte_count;
>> +        ber_cut_nbytes(data, dlen, vlen);
>> +
>> +        return invoke_callback(cb, ctx, value, vlen);
>> +    }
>> +
>> +    /* Ignore highest bit */
>> +    byte_count &= ~BER_SHORT_LEN_MASK;
>> +
>> +    /*
>> +     * size_t is enough to express the length, although the ber encoding
>> +     * standard supports larger length.
>> +     */
>> +    if (byte_count > sizeof(size_t)) {
>> +        return -1;
>> +    }
>> +
>> +    while (byte_count--) {
>> +        vlen <<= 8;
>> +        vlen += ber_cut_byte(data, dlen);
>> +    }
>> +
>> +    if (vlen > *dlen) {
>> +        return -1;
>> +    }
>> +
>> +    value = *data;
>> +    ber_cut_nbytes(data, dlen, vlen);
>> +
>> +    return invoke_callback(cb, ctx, value, vlen);
>> +}
>> +
>> +static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
>> +                                       BerDecodeCb cb, void *ctx)
>> +{
>> +    size_t vlen = 0;
>> +    const uint8_t *value;
>> +
>> +    if (*dlen < 3) {
>> +        return -1;
>> +    }
>> +
>> +    /* skip undefinite-length-mask 0x80 */
>> +    ber_cut_nbytes(data, dlen, 1);
>> +
>> +    value = *data;
>> +    while (vlen < *dlen) {
>> +        if ((*data)[vlen] != 0) {
>> +            vlen++;
>> +            continue;
>> +        }
>> +
>> +        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
>> +            ber_cut_nbytes(data, dlen, vlen + 2);
>> +            return invoke_callback(cb, ctx, value, vlen);
>> +        }
>> +
>> +        vlen += 2;
>> +    }
>> +
>> +    return -1;
>> +}
>> +
>> +static int ber_extract_data(const uint8_t **data, size_t *dlen,
>> +                            BerDecodeCb cb, void *ctx)
>> +{
>> +    uint8_t val = ber_peek_byte(data, dlen);
>> +
>> +    if (val == BER_SHORT_LEN_MASK) {
>> +        return ber_extract_undefinite_data(data, dlen, cb, ctx);
>> +    }
>> +
>> +    return ber_extract_definite_data(data, dlen, cb, ctx);
>> +}
>> +
>> +int ber_decode_int(const uint8_t **data, size_t *dlen,
>> +                   BerDecodeCb cb, void *ctx)
>> +{
>> +    uint8_t tag = ber_cut_byte(data, dlen);
>> +
>> +    /* INTEGER must encoded in primitive-form */
>> +    if (tag != ber_type_tag_int) {
>> +        return -1;
>> +    }
>> +
>> +    return ber_extract_data(data, dlen, cb, ctx);
>> +}
>> +
>> +int ber_decode_seq(const uint8_t **data, size_t *dlen,
>> +                   BerDecodeCb cb, void *ctx)
>> +{
>> +    uint8_t val = ber_cut_byte(data, dlen);
>> +
>> +    /* SEQUENCE must use constructed form */
>> +    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
>> +        return -1;
>> +    }
>> +
>> +    return ber_extract_data(data, dlen, cb, ctx);
>> +}
> 
> Nettle has some asn1 APIs - can we not use those instead of
> implementing all it ourselves ?
> 

Of course, we can use the API provided by nettle. There is a little doubt 
here: If we use nettle's API directly, the implementation of rsakey.{hc} will 
be tied to nettle, or we should define a new structure independent of 
nettle/mpz_t to save the parameters of RSA?

> 
>> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
>> index 03cc3bf46b..2ec7f0f8d7 100644
>> --- a/include/crypto/akcipher.h
>> +++ b/include/crypto/akcipher.h
>> @@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
>> 
>> int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
>> 
>> +#ifdef CONFIG_HOGWEED
>> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
>> +                                             QCryptoAkcipherKeyType type,
>> +                                             const uint8_t *key, size_t keylen,
>> +                                             void *para, Error **errp);
>> +#else
>> +static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
>> +                                             QCryptoAkcipherAlgorithm alg,
>> +                                             QCryptoAkcipherKeyType type,
>> +                                             const uint8_t *key, size_t keylen,
>> +                                             void *para, Error **errp)
>> +{
>> +    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
>> +    return NULL;
>> +}
>> +#endif
> 
> 
> These methods are private impl details and should not be in the
> akcipher.h public header. This ties back to my earlier comment
> about making this akcipher impl pluggable in the same way as
> the cipher impl is.
> 
> 
> 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 :|


^ permalink raw reply	[flat|nested] 62+ messages in thread

* Re: [External] [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed
@ 2022-03-28  9:14       ` 何磊
  0 siblings, 0 replies; 62+ messages in thread
From: 何磊 @ 2022-03-28  9:14 UTC (permalink / raw)
  To: "Daniel P. Berrangé"
  Cc: herbert, Michael S. Tsirkin, jasowang, qemu-devel, zhenwei pi,
	virtualization, arei.gonglei, linux-crypto, 何磊



> On Mar 23, 2022, at 9:50 PM, Daniel P. Berrangé <berrange@redhat.com> wrote:
> 
> On Wed, Mar 23, 2022 at 10:49:10AM +0800, zhenwei pi wrote:
>> From: Lei He <helei.sig11@bytedance.com>
>> 
>> Introduce ASN.1 decoder, and 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 <helei.sig11@bytedance.com>
>> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
>> ---
>> crypto/akcipher-nettle.c  | 523 ++++++++++++++++++++++++++++++++++++++
>> crypto/akcipher.c         |   3 +
>> crypto/asn1_decoder.c     | 185 ++++++++++++++
>> crypto/asn1_decoder.h     |  42 +++
> 
> Please introduce the asn1 files in a separate commit, and also
> provide a unit test to validate them in the same commit.
> 
>> diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
>> new file mode 100644
>> index 0000000000..45b93af772
>> --- /dev/null
>> +++ b/crypto/akcipher-nettle.c
>> @@ -0,0 +1,523 @@
>> +/*
>> + * QEMU Crypto akcipher algorithms
>> + *
>> + * Copyright (c) 2022 Bytedance
>> + * Author: lei he <helei.sig11@bytedance.com>
>> + *
>> + * 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 <stdbool.h>
>> +
>> +#include <nettle/rsa.h>
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu/host-utils.h"
>> +#include "asn1_decoder.h"
>> +#include "crypto/akcipher.h"
>> +#include "crypto/random.h"
>> +#include "qapi/error.h"
>> +#include "sysemu/cryptodev.h"
>> +
>> +typedef struct QCryptoNettleRsa {
>> +    QCryptoAkcipher akcipher;
>> +    struct rsa_public_key pub;
>> +    struct rsa_private_key priv;
>> +    QCryptoRsaPaddingAlgorithm padding_algo;
>> +    QCryptoRsaHashAlgorithm hash_algo;
>> +} QCryptoNettleRsa;
> 
> Call this QCryptoAkCipherNettleRSA
> 
>> +
>> +struct asn1_parse_ctx {
>> +    const uint8_t *data;
>> +    size_t dlen;
>> +};
>> +
>> +#define Octet 8
>> +
>> +static int extract_value(void *p, const uint8_t *data, size_t dlen)
>> +{
>> +    struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
>> +    ctx->data = (uint8_t *)data;
>> +    ctx->dlen = dlen;
>> +
>> +    return 0;
>> +}
>> +
>> +static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
>> +{
>> +    mpz_t *target = (mpz_t *)p;
>> +    nettle_mpz_set_str_256_u(*target, dlen, data);
>> +
>> +    return 0;
>> +}
>> +
>> +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
>> +
>> +static void qcrypto_nettle_rsa_destroy(void *ptr)
>> +{
>> +    QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
>> +    if (!rsa) {
>> +        return;
>> +    }
>> +
>> +    rsa_public_key_clear(&rsa->pub);
>> +    rsa_private_key_clear(&rsa->priv);
>> +    g_free(rsa);
>> +}
>> +
>> +static QCryptoAkcipher *qcrypto_nettle_new_rsa(
>> +    QCryptoAkcipherKeyType type,
>> +    const uint8_t *key,  size_t keylen,
>> +    QCryptoRsaOptions *opt, Error **errp);
>> +
>> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
>> +                                             QCryptoAkcipherKeyType type,
>> +                                             const uint8_t *key,
>> +                                             size_t keylen, void *para,
>> +                                             Error **errp)
>> +{
>> +    switch (alg) {
>> +    case QCRYPTO_AKCIPHER_ALG_RSA:
>> +        return qcrypto_nettle_new_rsa(type, key, keylen,
>> +                                      (QCryptoRsaOptions *)para, errp);
>> +    default:
>> +        error_setg(errp, "Unsupported algorithm: %u", alg);
>> +        return NULL;
>> +    }
>> +
>> +    return NULL;
>> +}
>> +
>> +/**
>> + * Parse ber encoded rsa private key, asn1 schema:
>> + *        RsaPrivKey ::= SEQUENCE {
>> + *             version     INTEGER
>> + *             n           INTEGER
>> + *             e           INTEGER
>> + *             d           INTEGER
>> + *             p           INTEGER
>> + *             q           INTEGER
>> + *             e1          INTEGER
>> + *             e2          INTEGER
>> + *             u           INTEGER
>> + *         }
>> + */
>> +static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
>> +                                 const uint8_t *key, size_t keylen)
>> +{
>> +    struct asn1_parse_ctx ctx;
>> +
>> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
>> +        keylen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 ||
>> +        ctx.dlen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (!rsa_public_key_prepare(&rsa->pub)) {
>> +        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
>> +     */
>> +    rsa->priv.size = rsa->pub.size;
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>> + * Parse ber encoded rsa pubkey, asn1 schema:
>> + *        RsaPrivKey ::= SEQUENCE {
>> + *             n           INTEGER
>> + *             e           INTEGER
>> + *         }
>> + */
>> +static int parse_rsa_public_key(QCryptoNettleRsa *rsa,
>> +                                const uint8_t *key,
>> +                                size_t keylen)
>> +{
>> +    struct asn1_parse_ctx ctx;
>> +
>> +    if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 ||
>> +        keylen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 ||
>> +        ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 ||
>> +        ctx.dlen != 0) {
>> +        return -1;
>> +    }
>> +
>> +    if (!rsa_public_key_prepare(&rsa->pub)) {
>> +        return -1;
>> +    }
>> +
>> +    return 0;
>> +}
> 
> I'd like to see these APIs for parsing RSA keys split out into
> a separate file, crypto/rsakey.{c,h}.  Define a struct to hold
> the RSA key parameters so it isn't tied to nettle, allowing
> its potential reuse with a gcrypt/gnutls impl of these APIs

So we should define the following structures to avoid tieing to nettle?

struct QCryptoRSAParameter {
	uint8_t *data;
       size_t data_len;
};

struct QCryptoRSAKey {
	QCryptoRSAParameter n;
	QCryptoRSAParameter e;
	QCryptoRSAParameter d;
	QCryptoRSAParameter p;
	QCryptoRSAParameter q;
       ...
};

> 
>> +
>> +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 QCryptoAkcipher *qcrypto_nettle_new_rsa(
>> +    QCryptoAkcipherKeyType type,
>> +    const uint8_t *key, size_t keylen,
>> +    QCryptoRsaOptions *opt, Error **errp)
>> +{
>> +    QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc();
>> +    rsa->padding_algo = opt->padding_algo;
>> +    rsa->hash_algo = opt->hash_algo;
>> +
>> +    switch (type) {
>> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
>> +        if (parse_rsa_private_key(rsa, key, keylen) == 0) {
>> +            qcrypto_nettle_rsa_set_akcipher_size(
>> +                (QCryptoAkcipher *)rsa, rsa->priv.size);
>> +            return (QCryptoAkcipher *)rsa;
>> +        }
>> +        error_setg(errp, "Failed to parse rsa private key");
> 
> This code pattern is back to front of what we would normally
> do.  ie I'd expect it to look like this:
> 
>         if (parse_rsa_private_key(rsa, key, keylen) != 0) {
>             error_setg(errp, "Failed to parse rsa private key");
> 	     goto error;
>         }
> 
>         qcrypto_nettle_rsa_set_akcipher_size(
>                 (QCryptoAkcipher *)rsa, rsa->priv.size);
>         return (QCryptoAkcipher *)rsa;
> 
> 
> 
>> +        break;
>> +
>> +    case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
>> +        if (parse_rsa_public_key(rsa, key, keylen) == 0) {
>> +            qcrypto_nettle_rsa_set_akcipher_size(
>> +                (QCryptoAkcipher *)rsa, rsa->pub.size);
>> +            return (QCryptoAkcipher *)rsa;
>> +        }
>> +        error_setg(errp, "Failed to parse rsa public rsa key");
>> +        break;
>> +
>> +    default:
>> +        error_setg(errp, "Unknown akcipher key type %d", type);
>> +    }
>> +
>> +    qcrypto_nettle_rsa_destroy(rsa);
>> +    return NULL;
>> +}
>> +
>> +
>> +/**
>> + * nettle does not provide RSA interfaces without padding,
>> + * here we implemented rsa algorithm with nettle/mpz.
>> + */
> 
> Urgh, this is really unpleasant. I don't want to see QEMU
> implementing any further crypto algorithms directly, only
> ever consume and wrap impls from external libraries. We've
> got a few in QEMU for historical reasons, but don't want
> to add more. There are too many ways to mess up crypto
> opening the door to subtle timing / side channel attacks,
> and crypto impls also cause distributors pain with export
> compliance rules.
> 
> If nettle doesn't provide an impl without padding, then
> simply don't implement it. Report an error if the caller
> tries to enable it.
> 
> An alternate gcrypt impl of these APIs might allow for
> an impl without padding.
> 
>> +static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data,
>> +                        size_t data_len, void *enc,
>> +                        size_t enc_len, Error **errp)
>> +{
>> +    mpz_t m;
>> +    int ret;
>> +
>> +    nettle_mpz_init_set_str_256_u(m, data_len, data);
>> +    /* (1) Validate 0 <= m < n */
>> +    if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) {
>> +        error_setg(errp, "Failed to validate input data");
>> +        return -1;
>> +    }
>> +
>> +    /* (2) c = m ^ e mod n */
>> +    mpz_powm(m, m, rsa->pub.e, rsa->pub.n);
>> +    if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) {
>> +        ret = -1;
>> +    } else {
>> +        ret = enc_len;
>> +        nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m);
>> +    }
>> +
>> +    mpz_clear(m);
>> +
>> +    return ret;
>> +}
>> +
>> +static int _rsa_dec_raw(QCryptoNettleRsa *rsa,
>> +                        const void *enc,
>> +                        size_t enc_len,
>> +                        void *data,
>> +                        size_t data_len,
>> +                        Error **errp)
>> +{
>> +    mpz_t c;
>> +    int ret;
>> +    nettle_mpz_init_set_str_256_u(c, enc_len, enc);
>> +
>> +    /* (1) Validate 0 <= c < n */
>> +    if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) {
>> +        error_setg(errp, "Failed to validate input data");
>> +        return -1;
>> +    }
>> +
>> +    /* (2) m = c ^ d mod n */
>> +    mpz_powm(c, c, rsa->priv.d, rsa->pub.n);
>> +    if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) {
>> +        ret = -1;
>> +    } else {
>> +        ret = data_len;
>> +        nettle_mpz_get_str_256(data_len, (uint8_t *)data, c);
>> +    }
>> +
>> +    mpz_clear(c);
>> +
>> +    return ret;
>> +}
>> +
>> +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out)
>> +{
>> +    /* TODO: check result */
>> +    qcrypto_random_bytes(out, len, NULL);
>> +}
>> +
>> +static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver,
>> +                                      const void *data, size_t data_len,
>> +                                      void *enc, size_t enc_len,
>> +                                      Error **errp)
>> +{
>> +
>> +    QCryptoNettleRsa *rsa =
>> +        container_of(akcipher_driver, QCryptoNettleRsa, akcipher);
>> +    mpz_t c;
>> +    int enc_ret;
>> +
>> +    if (data_len > rsa->pub.size || enc_len != rsa->pub.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    switch (rsa->padding_algo) {
>> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
>> +        return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp);
>> +
>> +    case QCRYPTO_RSA_PADDING_ALG_PKCS1:
>> +        mpz_init(c);
>> +        enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
>> +                              data_len, (uint8_t *)data, c);
>> +        if (enc_ret != 1) {
>> +            error_setg(errp, "Failed to encrypt");
>> +            enc_ret = -1;
>> +        } else {
>> +            nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c);
>> +            enc_ret = enc_len;
>> +        }
>> +        mpz_clear(c);
>> +        return enc_ret;
>> +
>> +    default:
>> +        error_setg(errp, "Unknown padding");
>> +        return -1;
>> +    }
>> +
>> +    return -1;
>> +}
>> +
>> +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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
>> +    mpz_t c;
>> +    int ret;
>> +    if (enc_len > rsa->priv.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    switch (rsa->padding_algo) {
>> +    case QCRYPTO_RSA_PADDING_ALG_RAW:
>> +        ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp);
>> +        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");
>> +            ret = -1;
>> +        } else {
>> +            ret = data_len;
>> +        }
>> +
>> +        mpz_clear(c);
>> +        break;
>> +
>> +    default:
>> +        ret = -1;
>> +        error_setg(errp, "Unknown padding");
>> +    }
>> +
>> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
>> +    int ret;
>> +    mpz_t s;
>> +
>> +    /**
>> +     * The RSA algorithm cannot be used for signature/verification
>> +     * without padding.
>> +     */
>> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
>> +        error_setg(errp, "Try to make signature without padding");
>> +        return -1;
>> +    }
>> +
>> +    if (data_len > rsa->priv.size || sig_len != rsa->priv.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    mpz_init(s);
>> +    switch (rsa->hash_algo) {
>> +    case QCRYPTO_RSA_HASH_ALG_MD5:
>> +        ret = rsa_md5_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
>> +        ret = rsa_sha1_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
>> +        ret = rsa_sha256_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
>> +        ret = rsa_sha512_sign_digest(&rsa->priv, data, s);
>> +        break;
>> +
>> +    default:
>> +        error_setg(errp, "Unknown hash algorithm");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +
>> +    if (ret != 1) {
>> +        error_setg(errp, "Failed to make signature");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +    nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s);
>> +    ret = sig_len;
>> +
>> +clear:
>> +    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 = container_of(akcipher, QCryptoNettleRsa, akcipher);
>> +
>> +    int ret;
>> +    mpz_t s;
>> +
>> +    /**
>> +     * The RSA algorithm cannot be used for signature/verification
>> +     * without padding.
>> +     */
>> +    if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) {
>> +        error_setg(errp, "Operation not supported");
>> +        return -1;
>> +    }
>> +    if (data_len > rsa->pub.size || sig_len < rsa->pub.size) {
>> +        error_setg(errp, "Invalid buffer size");
>> +        return -1;
>> +    }
>> +
>> +    nettle_mpz_init_set_str_256_u(s, sig_len, sig);
>> +    switch (rsa->hash_algo) {
>> +    case QCRYPTO_RSA_HASH_ALG_MD5:
>> +        ret = rsa_md5_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA1:
>> +        ret = rsa_sha1_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA256:
>> +        ret = rsa_sha256_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    case QCRYPTO_RSA_HASH_ALG_SHA512:
>> +        ret = rsa_sha512_verify_digest(&rsa->pub, data, s);
>> +        break;
>> +
>> +    default:
>> +        error_setg(errp, "Unsupported hash algorithm");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +
>> +    if (ret != 1) {
>> +        error_setg(errp, "Failed to verify");
>> +        ret = -1;
>> +        goto clear;
>> +    }
>> +    ret = 0;
>> +
>> +clear:
>> +    mpz_clear(s);
>> +
>> +    return ret;
>> +}
>> +
>> +static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher,
>> +                                   Error **errp)
>> +{
>> +    qcrypto_nettle_rsa_destroy(akcipher);
>> +    return 0;
>> +}
>> +
>> +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 QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void)
>> +{
>> +    QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa));
> 
> s/g_mallo0/g_new0/
> 
>> +    memset(rsa, 0, sizeof(QCryptoNettleRsa));
> 
> It is already initialized to zero by the allocator above.
> 
>> +    rsa->akcipher.driver = &nettle_rsa;
>> +    rsa_public_key_init(&rsa->pub);
>> +    rsa_private_key_init(&rsa->priv);
> 
> I don't think this method should exist at all though. It only
> has one caller, so just put the code inline there.
> 
>> +
>> +    return rsa;
>> +}
>> diff --git a/crypto/akcipher.c b/crypto/akcipher.c
>> index 1e52f2fd76..b5c04e8424 100644
>> --- a/crypto/akcipher.c
>> +++ b/crypto/akcipher.c
>> @@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg,
>> {
>>     QCryptoAkcipher *akcipher = NULL;
>> 
>> +    akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen,
>> +                                           para, errp);
>> +
>>     return akcipher;
>> }
> 
> Hard-wiring this to use the nettle impl is not at all desirable. It
> needs to use a pluggable approach, with a strong preferance to match
> the design of the crypto/cipher.c
> 
>> 
>> diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c
>> new file mode 100644
>> index 0000000000..bfb145e84e
>> --- /dev/null
>> +++ b/crypto/asn1_decoder.c
>> @@ -0,0 +1,185 @@
>> +/*
>> + * QEMU Crypto akcipher algorithms
> 
> This comment is wrong
> 
>> + *
>> + * Copyright (c) 2022 Bytedance
>> + * Author: lei he <helei.sig11@bytedance.com>
>> + *
>> + * 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 <stdint.h>
>> +#include <stddef.h>
>> +
>> +#include "crypto/asn1_decoder.h"
>> +
>> +enum ber_type_tag {
>> +    ber_type_tag_bool = 0x1,
>> +    ber_type_tag_int = 0x2,
>> +    ber_type_tag_bit_str = 0x3,
>> +    ber_type_tag_oct_str = 0x4,
>> +    ber_type_tag_oct_null = 0x5,
>> +    ber_type_tag_oct_oid = 0x6,
>> +    ber_type_tag_seq = 0x10,
>> +    ber_type_tag_set = 0x11,
>> +};
>> +
>> +#define BER_CONSTRUCTED_MASK 0x20
>> +#define BER_SHORT_LEN_MASK 0x80
>> +
>> +static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen)
>> +{
>> +    return **data;
>> +}
>> +
>> +static int invoke_callback(BerDecodeCb cb, void *ctx,
>> +                           const uint8_t *value, size_t vlen)
>> +{
>> +    if (!cb) {
>> +        return 0;
>> +    }
>> +
>> +    return cb(ctx, value, vlen);
>> +}
>> +
>> +static void ber_cut_nbytes(const uint8_t **data, size_t *dlen,
>> +                           size_t nbytes)
>> +{
>> +    *data += nbytes;
>> +    *dlen -= nbytes;
>> +}
>> +
>> +static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen)
>> +{
>> +    uint8_t val = ber_peek_byte(data, dlen);
>> +
>> +    ber_cut_nbytes(data, dlen, 1);
>> +
>> +    return val;
>> +}
>> +
>> +static int ber_extract_definite_data(const uint8_t **data, size_t *dlen,
>> +                                     BerDecodeCb cb, void *ctx)
>> +{
>> +    const uint8_t *value;
>> +    size_t vlen = 0;
>> +    uint8_t byte_count = ber_cut_byte(data, dlen);
>> +
>> +    /* short format of definite-length */
>> +    if (!(byte_count & BER_SHORT_LEN_MASK)) {
>> +        if (byte_count > *dlen) {
>> +            return -1;
>> +        }
>> +
>> +        value = *data;
>> +        vlen = byte_count;
>> +        ber_cut_nbytes(data, dlen, vlen);
>> +
>> +        return invoke_callback(cb, ctx, value, vlen);
>> +    }
>> +
>> +    /* Ignore highest bit */
>> +    byte_count &= ~BER_SHORT_LEN_MASK;
>> +
>> +    /*
>> +     * size_t is enough to express the length, although the ber encoding
>> +     * standard supports larger length.
>> +     */
>> +    if (byte_count > sizeof(size_t)) {
>> +        return -1;
>> +    }
>> +
>> +    while (byte_count--) {
>> +        vlen <<= 8;
>> +        vlen += ber_cut_byte(data, dlen);
>> +    }
>> +
>> +    if (vlen > *dlen) {
>> +        return -1;
>> +    }
>> +
>> +    value = *data;
>> +    ber_cut_nbytes(data, dlen, vlen);
>> +
>> +    return invoke_callback(cb, ctx, value, vlen);
>> +}
>> +
>> +static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen,
>> +                                       BerDecodeCb cb, void *ctx)
>> +{
>> +    size_t vlen = 0;
>> +    const uint8_t *value;
>> +
>> +    if (*dlen < 3) {
>> +        return -1;
>> +    }
>> +
>> +    /* skip undefinite-length-mask 0x80 */
>> +    ber_cut_nbytes(data, dlen, 1);
>> +
>> +    value = *data;
>> +    while (vlen < *dlen) {
>> +        if ((*data)[vlen] != 0) {
>> +            vlen++;
>> +            continue;
>> +        }
>> +
>> +        if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) {
>> +            ber_cut_nbytes(data, dlen, vlen + 2);
>> +            return invoke_callback(cb, ctx, value, vlen);
>> +        }
>> +
>> +        vlen += 2;
>> +    }
>> +
>> +    return -1;
>> +}
>> +
>> +static int ber_extract_data(const uint8_t **data, size_t *dlen,
>> +                            BerDecodeCb cb, void *ctx)
>> +{
>> +    uint8_t val = ber_peek_byte(data, dlen);
>> +
>> +    if (val == BER_SHORT_LEN_MASK) {
>> +        return ber_extract_undefinite_data(data, dlen, cb, ctx);
>> +    }
>> +
>> +    return ber_extract_definite_data(data, dlen, cb, ctx);
>> +}
>> +
>> +int ber_decode_int(const uint8_t **data, size_t *dlen,
>> +                   BerDecodeCb cb, void *ctx)
>> +{
>> +    uint8_t tag = ber_cut_byte(data, dlen);
>> +
>> +    /* INTEGER must encoded in primitive-form */
>> +    if (tag != ber_type_tag_int) {
>> +        return -1;
>> +    }
>> +
>> +    return ber_extract_data(data, dlen, cb, ctx);
>> +}
>> +
>> +int ber_decode_seq(const uint8_t **data, size_t *dlen,
>> +                   BerDecodeCb cb, void *ctx)
>> +{
>> +    uint8_t val = ber_cut_byte(data, dlen);
>> +
>> +    /* SEQUENCE must use constructed form */
>> +    if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) {
>> +        return -1;
>> +    }
>> +
>> +    return ber_extract_data(data, dlen, cb, ctx);
>> +}
> 
> Nettle has some asn1 APIs - can we not use those instead of
> implementing all it ourselves ?
> 

Of course, we can use the API provided by nettle. There is a little doubt 
here: If we use nettle's API directly, the implementation of rsakey.{hc} will 
be tied to nettle, or we should define a new structure independent of 
nettle/mpz_t to save the parameters of RSA?

> 
>> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
>> index 03cc3bf46b..2ec7f0f8d7 100644
>> --- a/include/crypto/akcipher.h
>> +++ b/include/crypto/akcipher.h
>> @@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher,
>> 
>> int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp);
>> 
>> +#ifdef CONFIG_HOGWEED
>> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
>> +                                             QCryptoAkcipherKeyType type,
>> +                                             const uint8_t *key, size_t keylen,
>> +                                             void *para, Error **errp);
>> +#else
>> +static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new(
>> +                                             QCryptoAkcipherAlgorithm alg,
>> +                                             QCryptoAkcipherKeyType type,
>> +                                             const uint8_t *key, size_t keylen,
>> +                                             void *para, Error **errp)
>> +{
>> +    error_setg(errp, "qcrypto akcipher has no nettle/hogweed support");
>> +    return NULL;
>> +}
>> +#endif
> 
> 
> These methods are private impl details and should not be in the
> akcipher.h public header. This ties back to my earlier comment
> about making this akcipher impl pluggable in the same way as
> the cipher impl is.
> 
> 
> 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 :|



^ permalink raw reply	[flat|nested] 62+ messages in thread

end of thread, other threads:[~2022-03-28 12:53 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-23  2:49 [PATCH v3 0/6] Support akcipher for virtio-crypto zhenwei pi
2022-03-23  2:49 ` zhenwei pi
2022-03-23  2:49 ` zhenwei pi
2022-03-23  2:49 ` [PATCH v3 1/6] virtio-crypto: header update zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23 15:38   ` Daniel P. Berrangé
2022-03-23 15:38     ` Daniel P. Berrangé
2022-03-23 15:38     ` Daniel P. Berrangé
2022-03-23 15:59     ` zhenwei pi
2022-03-23 15:59       ` zhenwei pi
2022-03-23 15:59       ` zhenwei pi
2022-03-23  2:49 ` [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23 13:08   ` Daniel P. Berrangé
2022-03-23 13:08     ` Daniel P. Berrangé
2022-03-23 13:08     ` Daniel P. Berrangé
2022-03-23 15:00   ` Daniel P. Berrangé
2022-03-23 15:00     ` Daniel P. Berrangé
2022-03-23 15:00     ` Daniel P. Berrangé
2022-03-23  2:49 ` [PATCH v3 3/6] crypto: Introduce akcipher crypto class zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23 13:33   ` Daniel P. Berrangé
2022-03-23 13:33     ` Daniel P. Berrangé
2022-03-23 13:33     ` Daniel P. Berrangé
2022-03-23  2:49 ` [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23 13:50   ` Daniel P. Berrangé
2022-03-23 13:50     ` Daniel P. Berrangé
2022-03-23 13:50     ` Daniel P. Berrangé
2022-03-28  9:14     ` [External] " 何磊
2022-03-28  9:14       ` 何磊
2022-03-23  2:49 ` [PATCH v3 5/6] tests/crypto: Add test suite for crypto akcipher zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23 15:10   ` Daniel P. Berrangé
2022-03-23 15:10     ` Daniel P. Berrangé
2022-03-23 15:10     ` Daniel P. Berrangé
2022-03-23  2:49 ` [PATCH v3 6/6] virtio-crypto: Introduce RSA algorithm zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23  2:49   ` zhenwei pi
2022-03-23  5:17 ` [PATCH v3 0/6] Support akcipher for virtio-crypto Eric Biggers
2022-03-23  5:17   ` Eric Biggers
2022-03-23  7:32   ` zhenwei pi
2022-03-23  7:32     ` zhenwei pi
2022-03-23  7:32     ` zhenwei pi
2022-03-23 18:03     ` Eric Biggers
2022-03-23 18:03       ` Eric Biggers
2022-03-24  1:20       ` zhenwei pi
2022-03-24  1:20         ` zhenwei pi
2022-03-24  1:20         ` zhenwei pi
2022-03-23 12:36 ` Philippe Mathieu-Daudé
2022-03-23 12:36   ` Philippe Mathieu-Daudé
2022-03-23 12:36 ` Michael S. Tsirkin
2022-03-23 12:36   ` Michael S. Tsirkin
2022-03-23 12:36   ` Michael S. Tsirkin
2022-03-23 14:37   ` zhenwei pi
2022-03-23 14:37     ` zhenwei pi
2022-03-23 14:37     ` zhenwei pi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.