replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / security / src / psiutils.c
1 /******************************************************************
2 *
3 * Copyright 2017 Samsung Electronics All Rights Reserved.
4 *
5 *
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *     http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************/
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "logger.h"
25 #include "ocstack.h"
26 #include "octypes.h"
27 #include "psiutils.h"
28 #include "psinterface.h"
29 #include "oic_malloc.h"
30 #include "mbedtls/entropy.h"
31 #include "mbedtls/ctr_drbg.h"
32 #include "mbedtls/aes.h"
33 #include "mbedtls/md.h"
34
35 #define TAG "OIC_SEC_PSIUTIL"
36
37 /*Internal to this File only*/
38 #define BLOCK_LEN 16
39 #define KEY_LEN 256
40 #define IV_LEN 16
41 #define DIGEST_LEN 32
42
43 #define VERIFY_NON_NULL(tag, arg, logLevel) do{ if (NULL == (arg)) \
44     { OIC_LOG((logLevel), tag, #arg " is NULL"); goto exit; } }while(0)
45
46 static unsigned char aesKey[AES_KEY_SIZE];
47 bool isKeySet = false;
48
49 OCStackResult psiSetKey(const unsigned char* key)
50 {
51     if (NULL == key)
52     {
53         return OC_STACK_INVALID_PARAM;
54     }
55     memcpy(aesKey,key,AES_KEY_SIZE);
56     isKeySet = true;
57     return OC_STACK_OK;
58 }
59
60 OCStackResult psiGetKey(unsigned char* key)
61 {
62     if(false == isKeySet)
63     {
64         return OC_STACK_ERROR;
65     }
66     memcpy(key, aesKey, AES_KEY_SIZE);
67     return OC_STACK_OK;
68 }
69
70 bool psiIsKeySet()
71 {
72     return isKeySet;
73 }
74
75 static int GenerateIV(unsigned char *IV)
76 {
77     mbedtls_ctr_drbg_context ctr_drbg;
78     mbedtls_entropy_context entropy;
79     char *pers = "generate psi iv vector";
80     int ret;
81
82     mbedtls_entropy_init( &entropy );
83     mbedtls_ctr_drbg_init(&ctr_drbg);
84
85     if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
86                     (unsigned char *) pers, strlen(pers))) != 0 )
87     {
88         OIC_LOG(ERROR, TAG, "mbedtls_ctr_drbg_init() Failed!!");
89         return 1;
90     }
91
92     if((ret = mbedtls_ctr_drbg_random(&ctr_drbg, IV, 16)) != 0 )
93     {
94         OIC_LOG(ERROR, TAG, "mbedtls_ctr_drbg_random Failed!!");
95         return 1;
96     }
97     return 0;
98 }
99
100 /*
101  * User need to OICFree() *ciphertext after using it.
102  */
103 int psiEncrypt(const unsigned char *plaintext, size_t pt_len,
104         unsigned char **ciphertext, size_t *ct_len)
105 {
106     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
107
108     unsigned char IV[IV_LEN];
109     unsigned char digest[DIGEST_LEN] , key[AES_KEY_SIZE];
110     unsigned char *tempBuf = NULL;
111     size_t padLen = BLOCK_LEN - (pt_len % BLOCK_LEN);
112     int ret = 0;
113     int tempBufSize, mod;
114
115     if (!plaintext || !pt_len || !ciphertext || *ciphertext || !ct_len)
116     {
117         OIC_LOG_V(ERROR, TAG, "%s: %s is NULL",
118                 __func__, !plaintext ? "plaintext" : !pt_len ? "pt_len"
119                 : !ciphertext || *ciphertext ? "ciphertext" : "ct_len");
120         ret = 1;
121         goto exit;
122     }
123
124     /*
125        -----------------------------------------
126        |  16 Bytes |  Plain/cipher    |32 Bytes|
127        |   IV      |  text + PadLen   | (H)MAC |
128        -----------------------------------------
129     */
130     tempBufSize = (IV_LEN + pt_len + padLen + DIGEST_LEN);
131     tempBuf = (unsigned char*)OICCalloc(1, sizeof(unsigned char) * tempBufSize);
132     VERIFY_NON_NULL(TAG, tempBuf, ERROR);
133
134     if (OC_STACK_OK != psiGetKey(key))
135     {
136         OIC_LOG(ERROR, TAG, "Failed to get Key");
137         ret = 1;
138         goto exit;
139     }
140
141     /* first IV_LEN bytes for Init. vector*/
142     memcpy(tempBuf + IV_LEN , plaintext, pt_len);
143     unsigned int i;
144     for (i = 0; i < padLen; ++i)
145     {
146         tempBuf[IV_LEN + pt_len + i] = padLen;
147     }
148
149     if (GenerateIV(IV))
150     {
151         OIC_LOG(ERROR, TAG, "IV Generation Failed!!");
152         ret = 1;
153         goto exit;
154     }
155
156     //last 4 bits of IV will store pt_len%BLOCK_LEN
157     //we will use these to recover padLen in decryption.
158     mod = (int)(pt_len & 0x0F);
159     IV[IV_LEN-1] = (unsigned char)((IV[IV_LEN -1] & 0xF0) | mod);
160
161     //store IV
162     memcpy(tempBuf, IV, IV_LEN);
163
164     mbedtls_aes_context aes_ctx;
165     mbedtls_aes_init(&aes_ctx);
166
167     mbedtls_aes_setkey_enc(&aes_ctx, key, KEY_LEN);
168
169     /*plain data start at an offset of IV_LEN*/
170     mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, (pt_len + padLen),
171             IV, (tempBuf+IV_LEN), (tempBuf+IV_LEN));
172
173     mbedtls_md_context_t sha_ctx;
174     mbedtls_md_init(&sha_ctx);
175
176     if(0 != mbedtls_md_setup(&sha_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1))
177     {
178         OIC_LOG(ERROR, TAG, "mbedtls_md_setup() Failed!!");
179         ret = 1;
180         goto exit;
181     }
182
183     /* setup the AES and HMAC context*/
184     memset(digest, 0, DIGEST_LEN);
185
186     mbedtls_md_hmac_starts(&sha_ctx, key, DIGEST_LEN);
187     ret = mbedtls_md_hmac_update(&sha_ctx, tempBuf + IV_LEN, (pt_len+padLen));
188     if (0 != ret)
189     {
190         OIC_LOG(ERROR, TAG, "mbedtls_md_hmac_update() Failed");
191         mbedtls_md_free(&sha_ctx);
192         goto exit;
193     }
194     mbedtls_md_hmac_finish(&sha_ctx, digest);
195     mbedtls_md_free(&sha_ctx);
196
197     //copy last 32 bytes for MAC
198     memcpy((tempBuf + IV_LEN + pt_len + padLen), digest, DIGEST_LEN);
199
200     memset(key, 0, AES_KEY_SIZE); //destroy key
201
202     *ciphertext = tempBuf;
203     tempBuf = NULL;
204     *ct_len = tempBufSize;
205 exit:
206     if (tempBuf)
207     {
208         OICFree(tempBuf);
209     }
210     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
211     return ret;
212 }
213
214 /*
215  * plaintext will be free by App
216  */
217 int psiDecrypt(const unsigned char *ciphertext, size_t ct_len,
218         unsigned char **plaintext, size_t *pt_len)
219 {
220     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
221
222     int mod, len;
223     unsigned char IV[IV_LEN], digest[DIGEST_LEN];
224     unsigned char key[AES_KEY_SIZE];
225     unsigned char *pt = NULL;
226     int ret = 0;
227
228     if (!ciphertext || !ct_len || !plaintext || *plaintext || !pt_len)
229     {
230         OIC_LOG_V(ERROR, TAG, "%s: %s is NULL",
231                 __func__, !ciphertext ? "ciphertext" : !ct_len ? "ct_len"
232                 : !plaintext || *plaintext ? "plaintext" : "pt_len");
233         ret = 1;
234         goto exit;
235     }
236
237
238     if (OC_STACK_OK != psiGetKey(key))
239     {
240         OIC_LOG(ERROR, TAG, "Failed to get Key");
241         ret = 1;
242         goto exit;
243     }
244
245     memcpy(IV, ciphertext, IV_LEN);
246     //restore mod
247     mod = IV[IV_LEN-1] & 0x0F;
248
249     //Length of original data was..
250     //Avoid writing Padding, IV & HMAC into the SVR DB File
251     len = ct_len - (BLOCK_LEN - mod) - (IV_LEN + DIGEST_LEN);
252     pt = (unsigned char*)OICCalloc(1, ct_len *sizeof(unsigned char));
253     VERIFY_NON_NULL(TAG, pt, ERROR);
254
255     //decrypt
256     mbedtls_aes_context aes_ctx;
257     mbedtls_aes_init(&aes_ctx);
258
259     mbedtls_aes_setkey_dec(&aes_ctx, key, KEY_LEN);
260     mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, ct_len - IV_LEN,
261             IV, (ciphertext+IV_LEN), pt);
262
263     //hash check
264     mbedtls_md_context_t sha_ctx;
265     mbedtls_md_init(&sha_ctx);
266
267     if (0 != mbedtls_md_setup(&sha_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1))
268     {
269         OIC_LOG(ERROR, TAG, "mbedtls_md_setup() Failed!!");
270         ret = 1;
271         goto exit;
272     }
273
274     memset(digest, 0, DIGEST_LEN);
275     mbedtls_md_hmac_starts(&sha_ctx, key, DIGEST_LEN);
276     ret = mbedtls_md_hmac_update(&sha_ctx, ciphertext + IV_LEN, (ct_len - DIGEST_LEN - IV_LEN));
277     if (0 != ret)
278     {
279         OIC_LOG(ERROR, TAG, "mbedtls_md_hmac_update() Failed");
280         mbedtls_md_free(&sha_ctx);
281         goto exit;
282     }
283     mbedtls_md_hmac_finish(&sha_ctx, digest);
284     mbedtls_md_free(&sha_ctx);
285     memset(key, 0, AES_KEY_SIZE); //destroy key
286
287     int diff = 0;
288     for (int i = 0; i < DIGEST_LEN; i++)
289     {
290         diff |= digest[i] ^ ciphertext[ct_len - DIGEST_LEN + i];
291     }
292     if (diff != 0)
293     {
294         OIC_LOG(ERROR, TAG, "HMAC check failed: wrong key, "
295                 "or file corrupted.");
296         ret = 1;
297         goto exit;
298     }
299     *plaintext = pt;
300     pt = NULL;
301     *pt_len = len;
302 exit:
303     if (pt)
304     {
305         OICFree(pt);
306     }
307     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
308     return ret;
309 }