1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2018-2020 NXP
4  *
5  * Crypto Cipher interface implementation to enable HW driver.
6  */
7 #include <assert.h>
8 #include <crypto/crypto.h>
9 #include <crypto/crypto_impl.h>
10 #include <drvcrypt.h>
11 #include <drvcrypt_cipher.h>
12 #include <kernel/panic.h>
13 #include <malloc.h>
14 #include <util.h>
15 
16 static const struct crypto_cipher_ops cipher_ops;
17 
18 /*
19  * Returns the reference to the driver context
20  *
21  * @ctx    Reference the API context pointer
22  */
to_cipher_ctx(struct crypto_cipher_ctx * ctx)23 static struct crypto_cipher *to_cipher_ctx(struct crypto_cipher_ctx *ctx)
24 {
25 	assert(ctx && ctx->ops == &cipher_ops);
26 
27 	return container_of(ctx, struct crypto_cipher, cipher_ctx);
28 }
29 
30 /*
31  * Free cipher context
32  *
33  * @ctx    Reference the API context pointer
34  */
cipher_free_ctx(struct crypto_cipher_ctx * ctx)35 static void cipher_free_ctx(struct crypto_cipher_ctx *ctx)
36 {
37 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
38 
39 	if (cipher->op && cipher->op->free_ctx)
40 		cipher->op->free_ctx(cipher->ctx);
41 
42 	free(cipher);
43 }
44 
45 /*
46  * Copy cipher context
47  *
48  * @dst_ctx  [out] Reference the API context pointer destination
49  * @src_ctx  Reference the API context pointer source
50  */
cipher_copy_state(struct crypto_cipher_ctx * dst_ctx,struct crypto_cipher_ctx * src_ctx)51 static void cipher_copy_state(struct crypto_cipher_ctx *dst_ctx,
52 			      struct crypto_cipher_ctx *src_ctx)
53 {
54 	struct crypto_cipher *cipher_src = to_cipher_ctx(src_ctx);
55 	struct crypto_cipher *cipher_dst = to_cipher_ctx(dst_ctx);
56 
57 	if (cipher_src->op && cipher_src->op->copy_state)
58 		cipher_src->op->copy_state(cipher_dst->ctx, cipher_src->ctx);
59 }
60 
61 /*
62  * Initialization of the cipher operation
63  *
64  * @ctx      Reference the API context pointer
65  * @mode     Operation mode
66  * @key1     First Key
67  * @key1_len Length of the first key
68  * @key2     Second Key
69  * @key2_len Length of the second key
70  * @iv       Initial Vector
71  * @iv_len   Length of the IV
72  */
cipher_init(struct crypto_cipher_ctx * ctx,TEE_OperationMode mode,const uint8_t * key1,size_t key1_len,const uint8_t * key2,size_t key2_len,const uint8_t * iv,size_t iv_len)73 static TEE_Result cipher_init(struct crypto_cipher_ctx *ctx,
74 			      TEE_OperationMode mode, const uint8_t *key1,
75 			      size_t key1_len, const uint8_t *key2,
76 			      size_t key2_len, const uint8_t *iv, size_t iv_len)
77 {
78 	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
79 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
80 
81 	if ((!key1 && key1_len) || (!key2 && key2_len) || (!iv && iv_len)) {
82 		CRYPTO_TRACE("One of the key is not correct");
83 		CRYPTO_TRACE("key1 @%p-%zu bytes", key1, key1_len);
84 		CRYPTO_TRACE("key2 @%p-%zu bytes", key1, key1_len);
85 		CRYPTO_TRACE("iv   @%p-%zu bytes", iv, iv_len);
86 		return TEE_ERROR_BAD_PARAMETERS;
87 	}
88 
89 	if (cipher->op && cipher->op->init) {
90 		struct drvcrypt_cipher_init dinit = {
91 			.ctx = cipher->ctx,
92 			.encrypt = (mode == TEE_MODE_ENCRYPT),
93 			.key1.data = (uint8_t *)key1,
94 			.key1.length = key1_len,
95 			.key2.data = (uint8_t *)key2,
96 			.key2.length = key2_len,
97 			.iv.data = (uint8_t *)iv,
98 			.iv.length = iv_len,
99 		};
100 
101 		ret = cipher->op->init(&dinit);
102 	}
103 
104 	CRYPTO_TRACE("cipher ret 0x%" PRIX32, ret);
105 	return ret;
106 }
107 
108 /*
109  * Update of the cipher operation
110  *
111  * @ctx        Reference the API context pointer
112  * @last_block True if last block to handle
113  * @data       Data to encrypt/decrypt
114  * @len        Length of the input data and output result
115  * @dst        [out] Output data of the operation
116  */
cipher_update(struct crypto_cipher_ctx * ctx,bool last_block,const uint8_t * data,size_t len,uint8_t * dst)117 static TEE_Result cipher_update(struct crypto_cipher_ctx *ctx, bool last_block,
118 				const uint8_t *data, size_t len, uint8_t *dst)
119 {
120 	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
121 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
122 
123 	if (!dst) {
124 		CRYPTO_TRACE("Destination buffer error");
125 		return TEE_ERROR_BAD_PARAMETERS;
126 	}
127 
128 	if (!data && len) {
129 		CRYPTO_TRACE("Bad data data @%p-%zu bytes", data, len);
130 		return TEE_ERROR_BAD_PARAMETERS;
131 	}
132 
133 	if (cipher->op && cipher->op->update) {
134 		struct drvcrypt_cipher_update dupdate = {
135 			.ctx = cipher->ctx,
136 			.last = last_block,
137 			.src.data = (uint8_t *)data,
138 			.src.length = len,
139 			.dst.data = dst,
140 			.dst.length = len,
141 		};
142 
143 		ret = cipher->op->update(&dupdate);
144 	}
145 
146 	CRYPTO_TRACE("cipher ret 0x%" PRIX32, ret);
147 	return ret;
148 }
149 
150 /*
151  * Finalize the cipher operation
152  *
153  * @ctx   Reference the API context pointer
154  */
cipher_final(struct crypto_cipher_ctx * ctx)155 static void cipher_final(struct crypto_cipher_ctx *ctx)
156 {
157 	struct crypto_cipher *cipher = to_cipher_ctx(ctx);
158 
159 	if (cipher->op && cipher->op->final)
160 		cipher->op->final(cipher->ctx);
161 }
162 
163 static const struct crypto_cipher_ops cipher_ops = {
164 	.init = cipher_init,
165 	.update = cipher_update,
166 	.final = cipher_final,
167 	.free_ctx = cipher_free_ctx,
168 	.copy_state = cipher_copy_state,
169 };
170 
drvcrypt_cipher_alloc_ctx(struct crypto_cipher_ctx ** ctx,uint32_t algo)171 TEE_Result drvcrypt_cipher_alloc_ctx(struct crypto_cipher_ctx **ctx,
172 				     uint32_t algo)
173 {
174 	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
175 	struct crypto_cipher *cipher = NULL;
176 
177 	CRYPTO_TRACE("Cipher alloc_ctx algo 0x%" PRIX32, algo);
178 
179 	assert(ctx);
180 
181 	cipher = calloc(1, sizeof(*cipher));
182 	if (!cipher)
183 		return TEE_ERROR_OUT_OF_MEMORY;
184 
185 	cipher->op = drvcrypt_get_ops(CRYPTO_CIPHER);
186 	if (cipher->op && cipher->op->alloc_ctx)
187 		ret = cipher->op->alloc_ctx(&cipher->ctx, algo);
188 
189 	if (ret != TEE_SUCCESS) {
190 		free(cipher);
191 	} else {
192 		cipher->cipher_ctx.ops = &cipher_ops;
193 		*ctx = &cipher->cipher_ctx;
194 	}
195 
196 	CRYPTO_TRACE("Cipher alloc_ctx ret 0x%" PRIX32, ret);
197 
198 	return ret;
199 }
200