Fix sha1 digest length and type mismatch(size_t and uint)
[platform/core/security/key-manager.git] / src / manager / service / ss-crypto.cpp
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  *
16  *
17  * @file        ss-crypto.cpp
18  * @author      Kyungwook Tak (k.tak@samsung.com)
19  * @version     1.0
20  * @brief       Decrypt old secure-storage data for migration
21  */
22 #include <ss-crypto.h>
23
24 #include <memory>
25 #include <cstring>
26
27 #include <openssl/sha.h>
28 #include <openssl/evp.h>
29 #include <openssl/hmac.h>
30
31 #include <dpl/log/log.h>
32
33 // lengths defined as macro to be used independent to type (size_t, unsigned int, int)
34 #define SALT_SIZE 32
35 #define KEY_SIZE 16
36 #define IV_SIZE KEY_SIZE
37
38 namespace CKM {
39
40 namespace {
41
42 RawBuffer _get_key(const std::string &id)
43 {
44         unsigned char salt[SALT_SIZE];
45
46         ::memset(salt, 0xFF, SALT_SIZE);
47
48         RawBuffer duk(KEY_SIZE);
49
50         if (::PKCS5_PBKDF2_HMAC_SHA1(id.c_str(), id.length(), salt, SALT_SIZE, 1, duk.size(),
51                         duk.data()) != 1) {
52                 LogError("Failed to pkcs5_pkbdf_hmac_sha1.");
53                 return RawBuffer();
54         }
55
56         return duk;
57 }
58
59 RawBuffer _get_iv(const RawBuffer &src)
60 {
61         RawBuffer iv(SHA_DIGEST_LENGTH);
62
63         unsigned int ivlen = 0;
64
65         if (::EVP_Digest(src.data(), src.size(), iv.data(), &ivlen, ::EVP_sha1(), nullptr)
66                         != 1) {
67                 LogError("Failed to get iv");
68                 return RawBuffer();
69         }
70
71         if (ivlen < IV_SIZE) {
72                 LogError("Invalid iv size: " << ivlen);
73                 return RawBuffer();
74         }
75
76         iv.resize(IV_SIZE);
77
78         return iv;
79 }
80
81 RawBuffer _decrypt(const RawBuffer &key, const RawBuffer &iv, const RawBuffer &ciphertext)
82 {
83         auto algo = ::EVP_aes_128_cbc();
84         int tmp_len = (ciphertext.size() / algo->block_size + 1) * algo->block_size;
85
86         if (key.size() != KEY_SIZE) {
87                 LogError("Invalid key size: " << key.size() << ", expected: " << KEY_SIZE);
88                 return RawBuffer();
89         }
90
91         if (iv.size() != IV_SIZE) {
92                 LogError("Invalid iv size: " << iv.size() << ", expected: " << IV_SIZE);
93                 return RawBuffer();
94         }
95
96         RawBuffer plaintext(tmp_len, 0);
97
98         std::unique_ptr<EVP_CIPHER_CTX, void(*)(EVP_CIPHER_CTX *)> ctxptr(
99                         ::EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
100
101         if (ctxptr == nullptr)
102                 throw std::bad_alloc();
103
104         auto ctx = ctxptr.get();
105
106         int ec = ::EVP_CIPHER_CTX_set_padding(ctx, 1);
107         if (ec != 1) {
108                 LogError("Failed to evp ctx set padding. ec: " << ec);
109                 return RawBuffer();
110         }
111
112         ec = ::EVP_CipherInit(ctx, algo, key.data(), iv.data(), 0 /* decrypt flag */);
113         if (ec != 1) {
114                 LogError("Failed to evp cipher init. ec: " << ec);
115                 return RawBuffer();
116         }
117
118         int plaintext_len = 0;
119         ec = ::EVP_CipherUpdate(ctx, plaintext.data(), &plaintext_len,
120                         ciphertext.data(), ciphertext.size());
121         if (ec != 1) {
122                 LogError("Failed to evp cipher update. ec: " << ec);
123                 return RawBuffer();
124         }
125
126         int final_len = 0;
127         ec = EVP_CipherFinal(ctx, plaintext.data() + plaintext_len, &final_len);
128         if (ec != 1) {
129                 LogError("Failed to evp cipher final. ec: " << ec);
130                 return RawBuffer();
131         }
132
133         plaintext_len += final_len;
134
135         plaintext.resize(plaintext_len);
136
137         return plaintext;
138 }
139
140 } // namespace anonymous
141
142 namespace SsMigration {
143
144 RawBuffer decrypt(const std::string &seed, const RawBuffer &ciphertext)
145 {
146         auto key = _get_key(seed);
147         auto iv = _get_iv(key);
148
149         return _decrypt(key, iv, ciphertext);
150 }
151
152 } // namespace SsMigration
153
154 } // namespace CKM