1f9a78287SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2f9a78287SJerome Forissier /* 3f9a78287SJerome Forissier * Copyright (c) 2019 Huawei Technologies Co., Ltd 4f9a78287SJerome Forissier */ 5f9a78287SJerome Forissier 6f9a78287SJerome Forissier #include <crypto/crypto.h> 7f9a78287SJerome Forissier #include <io.h> 8f9a78287SJerome Forissier #include <stdlib.h> 9f9a78287SJerome Forissier #include <string.h> 10f9a78287SJerome Forissier #include <tee_api_types.h> 11f9a78287SJerome Forissier #include <tee/tee_cryp_utl.h> 12f9a78287SJerome Forissier #include <trace.h> 13f9a78287SJerome Forissier #include <util.h> 14f9a78287SJerome Forissier #include <utee_defines.h> 15f9a78287SJerome Forissier 16f9a78287SJerome Forissier #include "acipher_helpers.h" 17f9a78287SJerome Forissier 18*a72295eaSJerome Forissier /* SM2 uses 256 bit unsigned integers in big endian format */ 19*a72295eaSJerome Forissier #define SM2_INT_SIZE_BYTES 32 20*a72295eaSJerome Forissier 21f9a78287SJerome Forissier static TEE_Result 22f9a78287SJerome Forissier sm2_uncompressed_bytes_to_point(ecc_point *p, const ltc_ecc_dp *dp, 23f9a78287SJerome Forissier const uint8_t *x1y1, size_t max_size, 24f9a78287SJerome Forissier size_t *consumed) 25f9a78287SJerome Forissier { 26f9a78287SJerome Forissier uint8_t *ptr = (uint8_t *)x1y1; 27f9a78287SJerome Forissier uint8_t one[] = { 1 }; 28f9a78287SJerome Forissier int ltc_res = 0; 29f9a78287SJerome Forissier 30*a72295eaSJerome Forissier if (max_size < (size_t)(2 * SM2_INT_SIZE_BYTES)) 31f9a78287SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 32f9a78287SJerome Forissier 33*a72295eaSJerome Forissier ltc_res = mp_read_unsigned_bin(p->x, ptr, SM2_INT_SIZE_BYTES); 34f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) 3580d47d0aSJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 36f9a78287SJerome Forissier 37*a72295eaSJerome Forissier ptr += SM2_INT_SIZE_BYTES; 38f9a78287SJerome Forissier 39*a72295eaSJerome Forissier ltc_res = mp_read_unsigned_bin(p->y, ptr, SM2_INT_SIZE_BYTES); 4080d47d0aSJerome Forissier if (ltc_res != CRYPT_OK) 4180d47d0aSJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 42f9a78287SJerome Forissier 4380d47d0aSJerome Forissier ltc_res = ltc_ecc_is_point(dp, p->x, p->y); 4480d47d0aSJerome Forissier if (ltc_res != CRYPT_OK) 4580d47d0aSJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 46f9a78287SJerome Forissier 47f9a78287SJerome Forissier mp_read_unsigned_bin(p->z, one, sizeof(one)); 48f9a78287SJerome Forissier 49*a72295eaSJerome Forissier *consumed = 2 * SM2_INT_SIZE_BYTES + 1; /* PC */ 50f9a78287SJerome Forissier 51f9a78287SJerome Forissier return TEE_SUCCESS; 52f9a78287SJerome Forissier } 53f9a78287SJerome Forissier 54f9a78287SJerome Forissier /* 55f9a78287SJerome Forissier * GM/T 0003.1‒2012 Part 1 Section 4.2.9 56f9a78287SJerome Forissier * Conversion of a byte string @buf to a point @p. Makes sure @p is on the curve 57f9a78287SJerome Forissier * defined by domain parameters @dp. 58f9a78287SJerome Forissier * Note: only the uncompressed form is supported. Uncompressed and hybrid forms 59f9a78287SJerome Forissier * are TBD. 60f9a78287SJerome Forissier */ 61f9a78287SJerome Forissier static TEE_Result sm2_bytes_to_point(ecc_point *p, const ltc_ecc_dp *dp, 62f9a78287SJerome Forissier const uint8_t *buf, size_t max_size, 63f9a78287SJerome Forissier size_t *consumed) 64f9a78287SJerome Forissier { 65f9a78287SJerome Forissier uint8_t PC = 0; 66f9a78287SJerome Forissier 67f9a78287SJerome Forissier if (!max_size) 68f9a78287SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 69f9a78287SJerome Forissier 70f9a78287SJerome Forissier PC = buf[0]; 71f9a78287SJerome Forissier 72f9a78287SJerome Forissier switch (PC) { 73f9a78287SJerome Forissier case 0x02: 74f9a78287SJerome Forissier case 0x03: 75f9a78287SJerome Forissier /* Compressed form */ 76f9a78287SJerome Forissier return TEE_ERROR_NOT_SUPPORTED; 77f9a78287SJerome Forissier case 0x04: 78f9a78287SJerome Forissier /* UNcompressed form */ 79f9a78287SJerome Forissier return sm2_uncompressed_bytes_to_point(p, dp, buf + 1, 80f9a78287SJerome Forissier max_size - 1, consumed); 81f9a78287SJerome Forissier case 0x06: 82f9a78287SJerome Forissier case 0x07: 83f9a78287SJerome Forissier /* Hybrid form */ 84f9a78287SJerome Forissier return TEE_ERROR_NOT_SUPPORTED; 85f9a78287SJerome Forissier default: 86f9a78287SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 87f9a78287SJerome Forissier } 88f9a78287SJerome Forissier 89f9a78287SJerome Forissier return TEE_ERROR_GENERIC; 90f9a78287SJerome Forissier } 91f9a78287SJerome Forissier 92f9a78287SJerome Forissier /* 93f9a78287SJerome Forissier * GM/T 0003.1‒2012 Part 4 Sections 5.4.2 and 5.4.3 94f9a78287SJerome Forissier * Key derivation function based on the SM3 hash function 95f9a78287SJerome Forissier */ 96f9a78287SJerome Forissier static TEE_Result sm2_kdf(const uint8_t *Z, size_t Z_len, uint8_t *t, 97f9a78287SJerome Forissier size_t tlen) 98f9a78287SJerome Forissier { 99f9a78287SJerome Forissier TEE_Result res = TEE_SUCCESS; 100f9a78287SJerome Forissier size_t remain = tlen; 101f9a78287SJerome Forissier uint32_t count = 1; 102f9a78287SJerome Forissier uint32_t be_count = 0; 103f9a78287SJerome Forissier void *ctx = NULL; 104f9a78287SJerome Forissier uint8_t *out = t; 105f9a78287SJerome Forissier 106f9a78287SJerome Forissier res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3); 107f9a78287SJerome Forissier if (res) 108f9a78287SJerome Forissier return res; 109f9a78287SJerome Forissier 110f9a78287SJerome Forissier while (remain) { 111f9a78287SJerome Forissier uint8_t tmp[TEE_SM3_HASH_SIZE] = { }; 112f9a78287SJerome Forissier uint8_t *buf = NULL; 113f9a78287SJerome Forissier 114f9a78287SJerome Forissier if (remain >= TEE_SM3_HASH_SIZE) 115f9a78287SJerome Forissier buf = out; 116f9a78287SJerome Forissier else 117f9a78287SJerome Forissier buf = tmp; 118f9a78287SJerome Forissier 119f9a78287SJerome Forissier put_be32(&be_count, count); 120f9a78287SJerome Forissier res = crypto_hash_init(ctx); 121f9a78287SJerome Forissier if (res) 122f9a78287SJerome Forissier goto out; 123f9a78287SJerome Forissier res = crypto_hash_update(ctx, Z, Z_len); 124f9a78287SJerome Forissier if (res) 125f9a78287SJerome Forissier goto out; 126f9a78287SJerome Forissier res = crypto_hash_update(ctx, (const uint8_t *)&be_count, 127f9a78287SJerome Forissier sizeof(be_count)); 128f9a78287SJerome Forissier if (res) 129f9a78287SJerome Forissier goto out; 130f9a78287SJerome Forissier res = crypto_hash_final(ctx, buf, TEE_SM3_HASH_SIZE); 131f9a78287SJerome Forissier if (res) 132f9a78287SJerome Forissier goto out; 133f9a78287SJerome Forissier 134f9a78287SJerome Forissier if (remain < TEE_SM3_HASH_SIZE) { 135f9a78287SJerome Forissier memcpy(out, tmp, remain); 136f9a78287SJerome Forissier break; 137f9a78287SJerome Forissier } 138f9a78287SJerome Forissier 139f9a78287SJerome Forissier out += TEE_SM3_HASH_SIZE; 140f9a78287SJerome Forissier remain -= TEE_SM3_HASH_SIZE; 141f9a78287SJerome Forissier count++; 142f9a78287SJerome Forissier } 143f9a78287SJerome Forissier out: 144f9a78287SJerome Forissier crypto_hash_free_ctx(ctx); 145f9a78287SJerome Forissier return res; 146f9a78287SJerome Forissier } 147f9a78287SJerome Forissier 148f9a78287SJerome Forissier static bool is_zero(const uint8_t *buf, size_t size) 149f9a78287SJerome Forissier { 150f9a78287SJerome Forissier uint8_t v = 0; 151f9a78287SJerome Forissier size_t i = 0; 152f9a78287SJerome Forissier 153f9a78287SJerome Forissier for (i = 0; i < size; i++) 154f9a78287SJerome Forissier v |= buf[i]; 155f9a78287SJerome Forissier 156f9a78287SJerome Forissier return !v; 157f9a78287SJerome Forissier } 158f9a78287SJerome Forissier 159f9a78287SJerome Forissier /* 160f9a78287SJerome Forissier * GM/T 0003.1‒2012 Part 4 Section 7.1 161f9a78287SJerome Forissier * Decryption algorithm 162f9a78287SJerome Forissier */ 163f9a78287SJerome Forissier TEE_Result crypto_acipher_sm2_pke_decrypt(struct ecc_keypair *key, 164f9a78287SJerome Forissier const uint8_t *src, size_t src_len, 165f9a78287SJerome Forissier uint8_t *dst, size_t *dst_len) 166f9a78287SJerome Forissier { 167f9a78287SJerome Forissier TEE_Result res = TEE_SUCCESS; 168f9a78287SJerome Forissier uint8_t x2y2[64] = { }; 169f9a78287SJerome Forissier ecc_key ltc_key = { }; 170f9a78287SJerome Forissier ecc_point *C1 = NULL; 171f9a78287SJerome Forissier size_t C1_len = 0; 172f9a78287SJerome Forissier ecc_point *S = NULL; 173f9a78287SJerome Forissier ecc_point *x2y2p = NULL; 174f9a78287SJerome Forissier void *ctx = NULL; 175f9a78287SJerome Forissier int ltc_res = 0; 176f9a78287SJerome Forissier void *h = NULL; 177f9a78287SJerome Forissier int inf = 0; 178f9a78287SJerome Forissier uint8_t *t = NULL; 179f9a78287SJerome Forissier size_t C2_len = 0; 180f9a78287SJerome Forissier size_t i = 0; 181f9a78287SJerome Forissier size_t out_len = 0; 182f9a78287SJerome Forissier uint8_t *eom = NULL; 183f9a78287SJerome Forissier uint8_t u[TEE_SM3_HASH_SIZE] = { }; 184f9a78287SJerome Forissier 185f9a78287SJerome Forissier /* 186f9a78287SJerome Forissier * Input buffer src is (C1 || C2 || C3) 187f9a78287SJerome Forissier * - C1 represents a point (should be on the curve) 188f9a78287SJerome Forissier * - C2 is the encrypted message 189f9a78287SJerome Forissier * - C3 is a SM3 hash 190f9a78287SJerome Forissier */ 191f9a78287SJerome Forissier 192f9a78287SJerome Forissier res = ecc_populate_ltc_private_key(<c_key, key, TEE_ALG_SM2_PKE, 193f9a78287SJerome Forissier NULL); 194f9a78287SJerome Forissier if (res) 195f9a78287SJerome Forissier goto out; 196f9a78287SJerome Forissier 197f9a78287SJerome Forissier /* Step B1: read and validate point C1 from encrypted message */ 198f9a78287SJerome Forissier 199f9a78287SJerome Forissier C1 = ltc_ecc_new_point(); 200f9a78287SJerome Forissier if (!C1) { 201f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 202f9a78287SJerome Forissier goto out; 203f9a78287SJerome Forissier } 204f9a78287SJerome Forissier 205f9a78287SJerome Forissier res = sm2_bytes_to_point(C1, <c_key.dp, src, src_len, &C1_len); 206f9a78287SJerome Forissier if (res) 207f9a78287SJerome Forissier goto out; 208f9a78287SJerome Forissier 209f9a78287SJerome Forissier /* Step B2: S = [h]C1 */ 210f9a78287SJerome Forissier 211f9a78287SJerome Forissier if (ltc_key.dp.cofactor != 1) { 212f9a78287SJerome Forissier S = ltc_ecc_new_point(); 213f9a78287SJerome Forissier if (!S) { 214f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 215f9a78287SJerome Forissier goto out; 216f9a78287SJerome Forissier } 217f9a78287SJerome Forissier 218f9a78287SJerome Forissier ltc_res = mp_init_multi(&h, NULL); 219f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) 220f9a78287SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 221f9a78287SJerome Forissier 222f9a78287SJerome Forissier ltc_res = mp_set_int(h, ltc_key.dp.cofactor); 223f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 224f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 225f9a78287SJerome Forissier goto out; 226f9a78287SJerome Forissier } 227f9a78287SJerome Forissier 228f9a78287SJerome Forissier ltc_res = ltc_ecc_mulmod(h, C1, S, ltc_key.dp.A, 229f9a78287SJerome Forissier ltc_key.dp.prime, 1); 230f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 231f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 232f9a78287SJerome Forissier goto out; 233f9a78287SJerome Forissier } 234f9a78287SJerome Forissier 235f9a78287SJerome Forissier ltc_res = ltc_ecc_is_point_at_infinity(S, ltc_key.dp.prime, 236f9a78287SJerome Forissier &inf); 237f9a78287SJerome Forissier } else { 238f9a78287SJerome Forissier ltc_res = ltc_ecc_is_point_at_infinity(C1, ltc_key.dp.prime, 239f9a78287SJerome Forissier &inf); 240f9a78287SJerome Forissier } 241f9a78287SJerome Forissier if (inf) { 242f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 243f9a78287SJerome Forissier goto out; 244f9a78287SJerome Forissier } 245f9a78287SJerome Forissier 246f9a78287SJerome Forissier /* Step B3: (x2, y2) = [dB]C1 */ 247f9a78287SJerome Forissier 248f9a78287SJerome Forissier x2y2p = ltc_ecc_new_point(); 249f9a78287SJerome Forissier if (!x2y2p) { 250f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 251f9a78287SJerome Forissier goto out; 252f9a78287SJerome Forissier } 253f9a78287SJerome Forissier 254f9a78287SJerome Forissier ltc_res = ltc_ecc_mulmod(ltc_key.k, C1, x2y2p, ltc_key.dp.A, 255f9a78287SJerome Forissier ltc_key.dp.prime, 1); 256f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 257f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 258f9a78287SJerome Forissier goto out; 259f9a78287SJerome Forissier } 260f9a78287SJerome Forissier 261*a72295eaSJerome Forissier if (mp_unsigned_bin_size(x2y2p->x) > SM2_INT_SIZE_BYTES || 262*a72295eaSJerome Forissier mp_unsigned_bin_size(x2y2p->y) > SM2_INT_SIZE_BYTES) { 263f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 264f9a78287SJerome Forissier goto out; 265f9a78287SJerome Forissier } 266f9a78287SJerome Forissier 267*a72295eaSJerome Forissier mp_to_unsigned_bin2(x2y2p->x, x2y2, SM2_INT_SIZE_BYTES); 268*a72295eaSJerome Forissier mp_to_unsigned_bin2(x2y2p->y, x2y2 + SM2_INT_SIZE_BYTES, 269*a72295eaSJerome Forissier SM2_INT_SIZE_BYTES); 270f9a78287SJerome Forissier 271f9a78287SJerome Forissier /* Step B4: t = KDF(x2 || y2, klen) */ 272f9a78287SJerome Forissier 273f9a78287SJerome Forissier /* C = C1 || C2 || C3 */ 274f9a78287SJerome Forissier if (src_len <= C1_len + TEE_SM3_HASH_SIZE) { 275f9a78287SJerome Forissier res = TEE_ERROR_BAD_PARAMETERS; 276f9a78287SJerome Forissier goto out; 277f9a78287SJerome Forissier } 278f9a78287SJerome Forissier 279f9a78287SJerome Forissier C2_len = src_len - C1_len - TEE_SM3_HASH_SIZE; 280f9a78287SJerome Forissier 281f9a78287SJerome Forissier t = calloc(1, C2_len); 282f9a78287SJerome Forissier if (!t) { 283f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 284f9a78287SJerome Forissier goto out; 285f9a78287SJerome Forissier } 286f9a78287SJerome Forissier 287f9a78287SJerome Forissier res = sm2_kdf(x2y2, sizeof(x2y2), t, C2_len); 288f9a78287SJerome Forissier if (res) 289f9a78287SJerome Forissier goto out; 290f9a78287SJerome Forissier 291f9a78287SJerome Forissier if (is_zero(t, C2_len)) { 292f9a78287SJerome Forissier res = TEE_ERROR_CIPHERTEXT_INVALID; 293f9a78287SJerome Forissier goto out; 294f9a78287SJerome Forissier } 295f9a78287SJerome Forissier 296f9a78287SJerome Forissier /* Step B5: get C2 from C and compute Mprime = C2 (+) t */ 297f9a78287SJerome Forissier 298f9a78287SJerome Forissier out_len = MIN(*dst_len, C2_len); 299f9a78287SJerome Forissier for (i = 0; i < out_len; i++) 300f9a78287SJerome Forissier dst[i] = src[C1_len + i] ^ t[i]; 301f9a78287SJerome Forissier *dst_len = out_len; 302f9a78287SJerome Forissier if (out_len < C2_len) { 303f9a78287SJerome Forissier eom = calloc(1, C2_len - out_len); 304f9a78287SJerome Forissier if (!eom) 305f9a78287SJerome Forissier goto out; 306f9a78287SJerome Forissier for (i = out_len; i < C2_len; i++) 307f9a78287SJerome Forissier eom[i - out_len] = src[C1_len + i] ^ t[i]; 308f9a78287SJerome Forissier } 309f9a78287SJerome Forissier 310f9a78287SJerome Forissier /* Step B6: compute u = Hash(x2 || M' || y2) and compare with C3 */ 311f9a78287SJerome Forissier 312f9a78287SJerome Forissier res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3); 313f9a78287SJerome Forissier if (res) 314f9a78287SJerome Forissier goto out; 315f9a78287SJerome Forissier res = crypto_hash_init(ctx); 316f9a78287SJerome Forissier if (res) 317f9a78287SJerome Forissier goto out; 318*a72295eaSJerome Forissier res = crypto_hash_update(ctx, x2y2, SM2_INT_SIZE_BYTES); 319f9a78287SJerome Forissier if (res) 320f9a78287SJerome Forissier goto out; 321f9a78287SJerome Forissier res = crypto_hash_update(ctx, dst, out_len); 322f9a78287SJerome Forissier if (res) 323f9a78287SJerome Forissier goto out; 324f9a78287SJerome Forissier if (out_len < C2_len) { 325f9a78287SJerome Forissier res = crypto_hash_update(ctx, eom, C2_len - out_len); 326f9a78287SJerome Forissier if (res) 327f9a78287SJerome Forissier goto out; 328f9a78287SJerome Forissier } 329*a72295eaSJerome Forissier res = crypto_hash_update(ctx, x2y2 + SM2_INT_SIZE_BYTES, 330*a72295eaSJerome Forissier SM2_INT_SIZE_BYTES); 331f9a78287SJerome Forissier if (res) 332f9a78287SJerome Forissier goto out; 333f9a78287SJerome Forissier res = crypto_hash_final(ctx, u, sizeof(u)); 334f9a78287SJerome Forissier if (res) 335f9a78287SJerome Forissier goto out; 336f9a78287SJerome Forissier 337f9a78287SJerome Forissier if (consttime_memcmp(u, src + C1_len + C2_len, TEE_SM3_HASH_SIZE)) { 338f9a78287SJerome Forissier res = TEE_ERROR_CIPHERTEXT_INVALID; 339f9a78287SJerome Forissier goto out; 340f9a78287SJerome Forissier } 341f9a78287SJerome Forissier out: 342f9a78287SJerome Forissier free(eom); 343f9a78287SJerome Forissier free(t); 344f9a78287SJerome Forissier crypto_hash_free_ctx(ctx); 345f9a78287SJerome Forissier ltc_ecc_del_point(x2y2p); 346f9a78287SJerome Forissier ltc_ecc_del_point(S); 347f9a78287SJerome Forissier ltc_ecc_del_point(C1); 348f9a78287SJerome Forissier mp_clear_multi(h, NULL); 34980d47d0aSJerome Forissier ecc_free(<c_key); 350f9a78287SJerome Forissier return res; 351f9a78287SJerome Forissier } 352f9a78287SJerome Forissier 353f9a78287SJerome Forissier /* 354f9a78287SJerome Forissier * GM/T 0003.1‒2012 Part 1 Section 4.2.8 355f9a78287SJerome Forissier * Conversion of point @p to a byte string @buf (uncompressed form). 356f9a78287SJerome Forissier */ 357f9a78287SJerome Forissier static TEE_Result sm2_point_to_bytes(uint8_t *buf, size_t *size, 358f9a78287SJerome Forissier const ecc_point *p) 359f9a78287SJerome Forissier { 360f9a78287SJerome Forissier size_t xsize = mp_unsigned_bin_size(p->x); 361f9a78287SJerome Forissier size_t ysize = mp_unsigned_bin_size(p->y); 362*a72295eaSJerome Forissier size_t sz = 2 * SM2_INT_SIZE_BYTES + 1; 363f9a78287SJerome Forissier 364*a72295eaSJerome Forissier if (xsize > SM2_INT_SIZE_BYTES || ysize > SM2_INT_SIZE_BYTES || 365*a72295eaSJerome Forissier *size < sz) 366f9a78287SJerome Forissier return TEE_ERROR_BAD_STATE; 367f9a78287SJerome Forissier 368*a72295eaSJerome Forissier memset(buf, 0, sz); 369f9a78287SJerome Forissier buf[0] = 0x04; /* Uncompressed form indicator */ 370*a72295eaSJerome Forissier mp_to_unsigned_bin2(p->x, buf + 1, SM2_INT_SIZE_BYTES); 371*a72295eaSJerome Forissier mp_to_unsigned_bin2(p->y, buf + 1 + SM2_INT_SIZE_BYTES, 372*a72295eaSJerome Forissier SM2_INT_SIZE_BYTES); 373f9a78287SJerome Forissier 374*a72295eaSJerome Forissier *size = sz; 375f9a78287SJerome Forissier 376f9a78287SJerome Forissier return TEE_SUCCESS; 377f9a78287SJerome Forissier } 378f9a78287SJerome Forissier 379f9a78287SJerome Forissier /* 380f9a78287SJerome Forissier * GM/T 0003.1‒2012 Part 4 Section 6.1 381f9a78287SJerome Forissier * Encryption algorithm 382f9a78287SJerome Forissier */ 383f9a78287SJerome Forissier TEE_Result crypto_acipher_sm2_pke_encrypt(struct ecc_public_key *key, 384f9a78287SJerome Forissier const uint8_t *src, size_t src_len, 385f9a78287SJerome Forissier uint8_t *dst, size_t *dst_len) 386f9a78287SJerome Forissier { 387f9a78287SJerome Forissier TEE_Result res = TEE_SUCCESS; 388f9a78287SJerome Forissier ecc_key ltc_key = { }; 389f9a78287SJerome Forissier ecc_point *x2y2p = NULL; 390f9a78287SJerome Forissier ecc_point *C1 = NULL; 391f9a78287SJerome Forissier ecc_point *S = NULL; 392f9a78287SJerome Forissier uint8_t x2y2[64] = { }; 393f9a78287SJerome Forissier uint8_t *t = NULL; 394f9a78287SJerome Forissier int ltc_res = 0; 395f9a78287SJerome Forissier void *k = NULL; 396f9a78287SJerome Forissier void *h = NULL; 397f9a78287SJerome Forissier int inf = 0; 398f9a78287SJerome Forissier size_t C1_len = 0; 399f9a78287SJerome Forissier void *ctx = NULL; 400f9a78287SJerome Forissier size_t i = 0; 401f9a78287SJerome Forissier 402f9a78287SJerome Forissier ltc_res = mp_init_multi(&k, &h, NULL); 403f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) 404f9a78287SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 405f9a78287SJerome Forissier 406f9a78287SJerome Forissier res = ecc_populate_ltc_public_key(<c_key, key, TEE_ALG_SM2_PKE, NULL); 407f9a78287SJerome Forissier if (res) 408f9a78287SJerome Forissier goto out; 409f9a78287SJerome Forissier 410f9a78287SJerome Forissier /* Step A1: generate random number 1 <= k < n */ 411f9a78287SJerome Forissier 412f9a78287SJerome Forissier ltc_res = rand_bn_upto(k, ltc_key.dp.order, NULL, 413f9a78287SJerome Forissier find_prng("prng_crypto")); 414f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 415f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 416f9a78287SJerome Forissier goto out; 417f9a78287SJerome Forissier } 418f9a78287SJerome Forissier 419f9a78287SJerome Forissier /* Step A2: compute C1 = [k]G */ 420f9a78287SJerome Forissier 421f9a78287SJerome Forissier C1 = ltc_ecc_new_point(); 422f9a78287SJerome Forissier if (!C1) { 423f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 424f9a78287SJerome Forissier goto out; 425f9a78287SJerome Forissier } 426f9a78287SJerome Forissier 427f9a78287SJerome Forissier ltc_res = ltc_ecc_mulmod(k, <c_key.dp.base, C1, ltc_key.dp.A, 428f9a78287SJerome Forissier ltc_key.dp.prime, 1); 429f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 430f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 431f9a78287SJerome Forissier goto out; 432f9a78287SJerome Forissier } 433f9a78287SJerome Forissier 434f9a78287SJerome Forissier /* Step A3: compute S = [h]PB and check for infinity */ 435f9a78287SJerome Forissier 436f9a78287SJerome Forissier if (ltc_key.dp.cofactor != 1) { 437f9a78287SJerome Forissier S = ltc_ecc_new_point(); 438f9a78287SJerome Forissier if (!S) { 439f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 440f9a78287SJerome Forissier goto out; 441f9a78287SJerome Forissier } 442f9a78287SJerome Forissier 443f9a78287SJerome Forissier ltc_res = mp_set_int(h, ltc_key.dp.cofactor); 444f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 445f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 446f9a78287SJerome Forissier goto out; 447f9a78287SJerome Forissier } 448f9a78287SJerome Forissier 449f9a78287SJerome Forissier ltc_res = ltc_ecc_mulmod(h, <c_key.pubkey, S, ltc_key.dp.A, 450f9a78287SJerome Forissier ltc_key.dp.prime, 1); 451f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 452f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 453f9a78287SJerome Forissier goto out; 454f9a78287SJerome Forissier } 455f9a78287SJerome Forissier 456f9a78287SJerome Forissier ltc_res = ltc_ecc_is_point_at_infinity(S, ltc_key.dp.prime, 457f9a78287SJerome Forissier &inf); 458f9a78287SJerome Forissier } else { 459f9a78287SJerome Forissier ltc_res = ltc_ecc_is_point_at_infinity(<c_key.pubkey, 460f9a78287SJerome Forissier ltc_key.dp.prime, &inf); 461f9a78287SJerome Forissier } 46217d4286fSJerome Forissier if (ltc_res != CRYPT_OK) { 46317d4286fSJerome Forissier res = TEE_ERROR_BAD_STATE; 46417d4286fSJerome Forissier goto out; 46517d4286fSJerome Forissier } 466f9a78287SJerome Forissier if (inf) { 467f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 468f9a78287SJerome Forissier goto out; 469f9a78287SJerome Forissier } 470f9a78287SJerome Forissier 471f9a78287SJerome Forissier /* Step A4: compute (x2, y2) = [k]PB */ 472f9a78287SJerome Forissier 473f9a78287SJerome Forissier x2y2p = ltc_ecc_new_point(); 474f9a78287SJerome Forissier if (!x2y2p) { 475f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 476f9a78287SJerome Forissier goto out; 477f9a78287SJerome Forissier } 478f9a78287SJerome Forissier 479f9a78287SJerome Forissier ltc_res = ltc_ecc_mulmod(k, <c_key.pubkey, x2y2p, ltc_key.dp.A, 480f9a78287SJerome Forissier ltc_key.dp.prime, 1); 481f9a78287SJerome Forissier if (ltc_res != CRYPT_OK) { 482f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 483f9a78287SJerome Forissier goto out; 484f9a78287SJerome Forissier } 485f9a78287SJerome Forissier 486*a72295eaSJerome Forissier if (mp_unsigned_bin_size(x2y2p->x) > SM2_INT_SIZE_BYTES || 487*a72295eaSJerome Forissier mp_unsigned_bin_size(x2y2p->y) > SM2_INT_SIZE_BYTES) { 488f9a78287SJerome Forissier res = TEE_ERROR_BAD_STATE; 489f9a78287SJerome Forissier goto out; 490f9a78287SJerome Forissier } 491f9a78287SJerome Forissier 492*a72295eaSJerome Forissier mp_to_unsigned_bin2(x2y2p->x, x2y2, SM2_INT_SIZE_BYTES); 493*a72295eaSJerome Forissier mp_to_unsigned_bin2(x2y2p->y, x2y2 + SM2_INT_SIZE_BYTES, 494*a72295eaSJerome Forissier SM2_INT_SIZE_BYTES); 495f9a78287SJerome Forissier 496f9a78287SJerome Forissier /* Step A5: compute t = KDF(x2 || y2, klen) */ 497f9a78287SJerome Forissier 498f9a78287SJerome Forissier t = calloc(1, src_len); 499f9a78287SJerome Forissier if (!t) { 500f9a78287SJerome Forissier res = TEE_ERROR_OUT_OF_MEMORY; 501f9a78287SJerome Forissier goto out; 502f9a78287SJerome Forissier } 503f9a78287SJerome Forissier 504f9a78287SJerome Forissier res = sm2_kdf(x2y2, sizeof(x2y2), t, src_len); 505f9a78287SJerome Forissier if (res) 506f9a78287SJerome Forissier goto out; 507f9a78287SJerome Forissier 508f9a78287SJerome Forissier if (is_zero(t, src_len)) { 509f9a78287SJerome Forissier res = TEE_ERROR_CIPHERTEXT_INVALID; 510f9a78287SJerome Forissier goto out; 511f9a78287SJerome Forissier } 512f9a78287SJerome Forissier 513f9a78287SJerome Forissier /* 514f9a78287SJerome Forissier * Steps A6, A7, A8: 515f9a78287SJerome Forissier * Compute C2 = M (+) t 516f9a78287SJerome Forissier * Compute C3 = Hash(x2 || M || y2) 517f9a78287SJerome Forissier * Output C = C1 || C2 || C3 518f9a78287SJerome Forissier */ 519f9a78287SJerome Forissier 520f9a78287SJerome Forissier /* C1 */ 521f9a78287SJerome Forissier C1_len = *dst_len; 522f9a78287SJerome Forissier res = sm2_point_to_bytes(dst, &C1_len, C1); 523f9a78287SJerome Forissier if (res) 524f9a78287SJerome Forissier goto out; 525f9a78287SJerome Forissier 526f9a78287SJerome Forissier if (*dst_len < C1_len + src_len + TEE_SM3_HASH_SIZE) { 527f9a78287SJerome Forissier *dst_len = C1_len + src_len + TEE_SM3_HASH_SIZE; 528f9a78287SJerome Forissier res = TEE_ERROR_SHORT_BUFFER; 529f9a78287SJerome Forissier goto out; 530f9a78287SJerome Forissier } 531f9a78287SJerome Forissier 532f9a78287SJerome Forissier /* C2 */ 533f9a78287SJerome Forissier for (i = 0; i < src_len; i++) 534f9a78287SJerome Forissier dst[i + C1_len] = src[i] ^ t[i]; 535f9a78287SJerome Forissier 536f9a78287SJerome Forissier /* C3 */ 537f9a78287SJerome Forissier res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3); 538f9a78287SJerome Forissier if (res) 539f9a78287SJerome Forissier goto out; 540f9a78287SJerome Forissier res = crypto_hash_init(ctx); 541f9a78287SJerome Forissier if (res) 542f9a78287SJerome Forissier goto out; 543*a72295eaSJerome Forissier res = crypto_hash_update(ctx, x2y2, SM2_INT_SIZE_BYTES); 544f9a78287SJerome Forissier if (res) 545f9a78287SJerome Forissier goto out; 546f9a78287SJerome Forissier res = crypto_hash_update(ctx, src, src_len); 547f9a78287SJerome Forissier if (res) 548f9a78287SJerome Forissier goto out; 549*a72295eaSJerome Forissier res = crypto_hash_update(ctx, x2y2 + SM2_INT_SIZE_BYTES, 550*a72295eaSJerome Forissier SM2_INT_SIZE_BYTES); 551f9a78287SJerome Forissier if (res) 552f9a78287SJerome Forissier goto out; 553f9a78287SJerome Forissier res = crypto_hash_final(ctx, dst + C1_len + src_len, TEE_SM3_HASH_SIZE); 554f9a78287SJerome Forissier if (res) 555f9a78287SJerome Forissier goto out; 556f9a78287SJerome Forissier 557f9a78287SJerome Forissier *dst_len = C1_len + src_len + TEE_SM3_HASH_SIZE; 558f9a78287SJerome Forissier out: 559f9a78287SJerome Forissier crypto_hash_free_ctx(ctx); 560f9a78287SJerome Forissier free(t); 561f9a78287SJerome Forissier ltc_ecc_del_point(x2y2p); 562f9a78287SJerome Forissier ltc_ecc_del_point(S); 563f9a78287SJerome Forissier ltc_ecc_del_point(C1); 56480d47d0aSJerome Forissier ecc_free(<c_key); 565f9a78287SJerome Forissier mp_clear_multi(k, h, NULL); 566f9a78287SJerome Forissier return res; 567f9a78287SJerome Forissier } 568