1/*
2 * Copyright (C) 2014 Igalia S.L. 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 "CryptoAlgorithmRSAES_PKCS1_v1_5.h"
28
29#if ENABLE(WEB_CRYPTO)
30
31#include "CryptoKeyRSA.h"
32#include "GCryptUtilities.h"
33
34namespace WebCore {
35
36static Optional<Vector<uint8_t>> gcryptEncrypt(gcry_sexp_t keySexp, const Vector<uint8_t>& plainText, size_t keySizeInBytes)
37{
38 // Embed the plain-text data in a `data` s-expression using PKCS#1 padding.
39 PAL::GCrypt::Handle<gcry_sexp_t> dataSexp;
40 gcry_error_t error = gcry_sexp_build(&dataSexp, nullptr, "(data(flags pkcs1)(value %b))",
41 plainText.size(), plainText.data());
42 if (error != GPG_ERR_NO_ERROR) {
43 PAL::GCrypt::logError(error);
44 return WTF::nullopt;
45 }
46
47 // Encrypt data with the provided key. The returned s-expression is of this form:
48 // (enc-val
49 // (rsa
50 // (a a-mpi)))
51 PAL::GCrypt::Handle<gcry_sexp_t> cipherSexp;
52 error = gcry_pk_encrypt(&cipherSexp, dataSexp, keySexp);
53 if (error != GPG_ERR_NO_ERROR) {
54 PAL::GCrypt::logError(error);
55 return WTF::nullopt;
56 }
57
58 // Return MPI data of the embedded `a` integer.
59 PAL::GCrypt::Handle<gcry_sexp_t> aSexp(gcry_sexp_find_token(cipherSexp, "a", 0));
60 if (!aSexp)
61 return WTF::nullopt;
62
63 return mpiZeroPrefixedData(aSexp, keySizeInBytes);
64}
65
66static Optional<Vector<uint8_t>> gcryptDecrypt(gcry_sexp_t keySexp, const Vector<uint8_t>& cipherText)
67{
68 // Embed the cipher-text data in an `enc-val` s-expression using PKCS#1 padding.
69 PAL::GCrypt::Handle<gcry_sexp_t> encValSexp;
70 gcry_error_t error = gcry_sexp_build(&encValSexp, nullptr, "(enc-val(flags pkcs1)(rsa(a %b)))",
71 cipherText.size(), cipherText.data());
72 if (error != GPG_ERR_NO_ERROR) {
73 PAL::GCrypt::logError(error);
74 return WTF::nullopt;
75 }
76
77 // Decrypt data with the provided key. The returned s-expression is of this form:
78 // (data
79 // (flags pkcs1)
80 // (value block))
81 PAL::GCrypt::Handle<gcry_sexp_t> plainSexp;
82 error = gcry_pk_decrypt(&plainSexp, encValSexp, keySexp);
83 if (error != GPG_ERR_NO_ERROR) {
84 PAL::GCrypt::logError(error);
85 return WTF::nullopt;
86 }
87
88 // Return MPI data of the embedded `value` integer.
89 PAL::GCrypt::Handle<gcry_sexp_t> valueSexp(gcry_sexp_find_token(plainSexp, "value", 0));
90 if (!valueSexp)
91 return WTF::nullopt;
92
93 return mpiData(valueSexp);
94}
95
96ExceptionOr<Vector<uint8_t>> CryptoAlgorithmRSAES_PKCS1_v1_5::platformEncrypt(const CryptoKeyRSA& key, const Vector<uint8_t>& plainText)
97{
98 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!(key.keySizeInBits() % 8));
99 auto output = gcryptEncrypt(key.platformKey(), plainText, key.keySizeInBits() / 8);
100 if (!output)
101 return Exception { OperationError };
102 return WTFMove(*output);
103}
104
105ExceptionOr<Vector<uint8_t>> CryptoAlgorithmRSAES_PKCS1_v1_5::platformDecrypt(const CryptoKeyRSA& key, const Vector<uint8_t>& cipherText)
106{
107 auto output = gcryptDecrypt(key.platformKey(), cipherText);
108 if (!output)
109 return Exception { OperationError };
110 return WTFMove(*output);
111}
112
113} // namespace WebCore
114
115#endif // ENABLE(WEB_CRYPTO)
116