[Win] Implement CryptoDigest
[WebKit-https.git] / Source / WebCore / platform / crypto / win / CryptoDigestWin.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "CryptoDigest.h"
28
29 #include <wincrypt.h>
30
31 namespace WebCore {
32
33 struct CryptoDigestContext {
34     CryptoDigest::Algorithm algorithm;
35     HCRYPTPROV hContext { 0 };
36     HCRYPTHASH hHash { 0 };
37 };
38
39 CryptoDigest::CryptoDigest()
40     : m_context(new CryptoDigestContext)
41 {
42 }
43
44 CryptoDigest::~CryptoDigest()
45 {
46     if (HCRYPTHASH hHash = m_context->hHash)
47         CryptDestroyHash(hHash);
48     if (HCRYPTPROV hContext = m_context->hContext)
49         CryptReleaseContext(hContext, 0);
50 }
51
52 std::unique_ptr<CryptoDigest> CryptoDigest::create(Algorithm algorithm)
53 {
54     auto digest = std::make_unique<CryptoDigest>();
55     digest->m_context->algorithm = algorithm;
56     if (!CryptAcquireContext(&digest->m_context->hContext, nullptr, nullptr /* use default provider */, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
57         return nullptr;
58
59     bool succeeded = false;
60     switch (algorithm) {
61     case CryptoDigest::Algorithm::SHA_1: {
62         succeeded = CryptCreateHash(digest->m_context->hContext, CALG_SHA1, 0, 0, &digest->m_context->hHash);
63         break;
64     }
65     case CryptoDigest::Algorithm::SHA_256: {
66         succeeded = CryptCreateHash(digest->m_context->hContext, CALG_SHA_256, 0, 0, &digest->m_context->hHash);
67         break;
68     }
69     case CryptoDigest::Algorithm::SHA_384: {
70         succeeded = CryptCreateHash(digest->m_context->hContext, CALG_SHA_384, 0, 0, &digest->m_context->hHash);
71         break;
72     }
73     case CryptoDigest::Algorithm::SHA_512: {
74         succeeded = CryptCreateHash(digest->m_context->hContext, CALG_SHA_512, 0, 0, &digest->m_context->hHash);
75         break;
76     }
77     }
78     if (succeeded)
79         return digest;
80     return nullptr;
81 }
82
83 void CryptoDigest::addBytes(const void* input, size_t length)
84 {
85     if (!input || !length)
86         return;
87     RELEASE_ASSERT(CryptHashData(m_context->hHash, reinterpret_cast<const BYTE*>(input), length, 0));
88 }
89
90 Vector<uint8_t> CryptoDigest::computeHash()
91 {
92     Vector<uint8_t> result;
93     DWORD digestLengthBuffer;
94     DWORD digestLengthBufferSize = sizeof(digestLengthBuffer);
95
96     RELEASE_ASSERT(CryptGetHashParam(m_context->hHash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&digestLengthBuffer), &digestLengthBufferSize, 0));
97     result.resize(digestLengthBuffer);
98
99     RELEASE_ASSERT(CryptGetHashParam(m_context->hHash, HP_HASHVAL, result.data(), &digestLengthBuffer, 0));
100     RELEASE_ASSERT(result.size() == digestLengthBuffer);
101     return result;
102 }
103
104 } // namespace WebCore