Merge "Fix accessing freed memory in X509CertificateStore::Update()" into tizen
[platform/framework/native/appfw.git] / src / security / crypto / FSecCryptoSha2Hash.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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 /**
18  * @file                FSecCryptoSha2Hash.cpp
19  * @brief               This file contains the implementation of Sha2Hash class.
20  */
21 #include <unique_ptr.h>
22 #include <openssl/sha.h>
23 #include <openssl/evp.h>
24 #include <FBaseResult.h>
25 #include <FBaseErrors.h>
26 #include <FSecCryptoSha2Hash.h>
27 #include <FBaseSysLog.h>
28
29 using namespace Tizen::Base;
30
31 namespace Tizen { namespace Security { namespace Crypto
32 {
33 static const int _SHA2_DIGEST_LENGTH = 64;
34
35 Sha2Hash::Sha2Hash(void)
36         : __pAlgorithm(EVP_sha256())
37         , __pEvpMdCtx(null)
38         , __pSha2HashImpl(null)
39 {
40 }
41
42 Sha2Hash::~Sha2Hash(void)
43 {
44         delete __pEvpMdCtx;
45 }
46
47 result
48 Sha2Hash::SetAlgorithm(const Tizen::Base::String& algorithm)
49 {
50         result r = E_SUCCESS;
51
52         if (algorithm.CompareTo(L"SHA2/224") == 0)
53         {
54                 __pAlgorithm = EVP_sha224();
55         }
56         else if (algorithm.CompareTo(L"SHA2/256") == 0)
57         {
58                 __pAlgorithm = EVP_sha256();
59         }
60         else if (algorithm.CompareTo(L"SHA2/384") == 0)
61         {
62                 __pAlgorithm = EVP_sha384();
63         }
64         else if (algorithm.CompareTo(L"SHA2/512") == 0)
65         {
66                 __pAlgorithm = EVP_sha512();
67         }
68         else
69         {
70                 r = E_UNSUPPORTED_ALGORITHM;
71         }
72
73         return r;
74 }
75
76 ByteBuffer*
77 Sha2Hash::GetHashN(const ByteBuffer& input) const
78 {
79         result r = E_SUCCESS;
80         int dataLen = 0;
81         unsigned int outLen = 0;
82         byte* pData = null;
83         byte hashOut[_SHA2_DIGEST_LENGTH] = {'\0'};
84
85         ClearLastResult();
86
87         SysTryReturn(NID_SEC_CRYPTO, __pAlgorithm != null, null, E_INVALID_ARG, "[E_INVALID_ARG] The algorithm value should be valid.");
88
89         pData = const_cast< byte* >(input.GetPointer());
90         SysTryReturn(NID_SEC_CRYPTO, pData != null, null, E_INVALID_ARG, "[E_INVALID_ARG] The input data value should be valid.");
91
92         dataLen = input.GetRemaining();
93         SysTryReturn(NID_SEC_CRYPTO, dataLen > 0, null, E_INVALID_ARG, "[E_INVALID_ARG] The input data length should be positive.");
94
95         outLen = EVP_MD_size(__pAlgorithm);
96
97         EVP_Digest(pData, dataLen, hashOut, &outLen, __pAlgorithm, null);
98         SysTryReturn(NID_SEC_CRYPTO, outLen > 0, null, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
99
100         //stores the hash in bytebuffer
101         std::unique_ptr<ByteBuffer> pOutput(new (std::nothrow) ByteBuffer());
102         SysTryReturn(NID_SEC_CRYPTO, pOutput != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
103
104         r = pOutput->Construct(outLen);
105         SysTryReturn(NID_SEC_CRYPTO, !IsFailed(r), null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
106
107         r = pOutput->SetArray(hashOut, 0, outLen);
108         SysTryReturn(NID_SEC_CRYPTO, !IsFailed(r), null, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
109
110         pOutput->Flip();
111
112         return pOutput.release();
113 }
114
115 result
116 Sha2Hash::Initialize(void)
117 {
118         result r = E_SUCCESS;
119         int ret = 0;
120
121         SysAssertf(__pEvpMdCtx == null, "Already constructed. Calling Initialize() twice or more on a same instance is not allowed for this class.");
122
123         __pEvpMdCtx = new (std::nothrow) EVP_MD_CTX();
124         SysTryReturn(NID_SEC_CRYPTO, __pEvpMdCtx != null, E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
125
126         ret = EVP_DigestInit(__pEvpMdCtx, __pAlgorithm);
127         SysTryCatch(NID_SEC_CRYPTO, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
128
129 CATCH:
130
131         if (IsFailed(r))
132         {
133                 delete __pEvpMdCtx;
134                 __pEvpMdCtx = null;
135         }
136         return r;
137 }
138
139 result
140 Sha2Hash::Update(const Tizen::Base::ByteBuffer& input)
141 {
142         result r = E_SUCCESS;
143         int ret = 0;
144         int dataLen = 0;
145         byte* pData = null;
146
147         SysAssertf(__pEvpMdCtx != null, "Not yet constructed. Initialize() should be called before use.");
148
149         pData = const_cast< byte* >(input.GetPointer());
150         SysTryReturn(NID_SEC_CRYPTO, pData != null, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The input data value should be valid.");
151
152         dataLen = input.GetRemaining();
153         SysTryReturn(NID_SEC_CRYPTO, dataLen > 0, E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The input data length should be positive.");
154
155         //SHA2_update is called
156         ret = EVP_DigestUpdate(__pEvpMdCtx, pData, dataLen);
157         SysTryReturn(NID_SEC_CRYPTO, ret == 1, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
158
159         return r;
160 }
161
162 Tizen::Base::ByteBuffer*
163 Sha2Hash::FinalizeN(void)
164 {
165         result r = E_SUCCESS;
166         int ret = 0;
167         int outLen = 0;
168         std::unique_ptr<ByteBuffer> pOutput(null);
169         std::unique_ptr<byte[]> pTempBuf(null);
170
171         ClearLastResult();
172
173         SysAssertf(__pEvpMdCtx != null && __pAlgorithm != null, "Not yet constructed. Initialize() and SetAlgorithm() should be called before use.");
174
175         outLen = EVP_MD_size(__pAlgorithm);
176         SysTryCatch(NID_SEC_CRYPTO, outLen > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
177
178         pTempBuf = std::unique_ptr<byte[]>(new (std::nothrow) byte[outLen]);
179         SysTryCatch(NID_SEC_CRYPTO, pTempBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
180
181         ret = EVP_DigestFinal(__pEvpMdCtx, pTempBuf.get(), null);
182         SysTryCatch(NID_SEC_CRYPTO, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
183
184         //hash is stored in bytebuffer
185         pOutput = std::unique_ptr<ByteBuffer>(new (std::nothrow) ByteBuffer());
186         SysTryCatch(NID_SEC_CRYPTO, pOutput != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
187
188         r = pOutput->Construct(outLen);
189         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory");
190
191         r = pOutput->SetArray(pTempBuf.get(), 0, outLen);
192         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
193
194         pOutput->Flip();
195
196 CATCH:
197
198         EVP_MD_CTX_cleanup(__pEvpMdCtx);
199
200         if (IsFailed(r))
201         {
202                 pOutput.reset(null);
203         }
204
205         delete __pEvpMdCtx;
206         __pEvpMdCtx = null;
207
208         return pOutput.release();
209 }
210
211 } } } //Tizen::Security::Crypto