68 // Embed the plain-text data in a data s-expression using PKCS#1 padding.
69 PAL::GCrypt::Handle<gcry_sexp_t> dataSexp;
70 gcry_error_t error = gcry_sexp_build(&dataSexp, nullptr, "(data(flags pkcs1)(value %b))",
71 plainText.size(), plainText.data());
72 if (error != GPG_ERR_NO_ERROR) {
73 PAL::GCrypt::logError(error);
74 return std::nullopt;
75 }
76
77 // Encrypt data with the provided key. The returned s-expression is of this form:
78 // (enc-val
79 // (rsa
80 // (a a-mpi)))
81 PAL::GCrypt::Handle<gcry_sexp_t> cipherSexp;
82 error = gcry_pk_encrypt(&cipherSexp, dataSexp, keySexp);
83 if (error != GPG_ERR_NO_ERROR) {
84 PAL::GCrypt::logError(error);
85 return std::nullopt;
86 }
87
88 // Return MPI data of the embedded a integer.
89 PAL::GCrypt::Handle<gcry_sexp_t> aSexp(gcry_sexp_find_token(cipherSexp, "a", 0));
90 if (!aSexp)
91 return std::nullopt;
92
93 return mpiData(aSexp);
94}
95
96static std::optional<Vector<uint8_t>> gcryptDecrypt(gcry_sexp_t keySexp, Vector<uint8_t>&& cipherText)
97{
98 // Embed the cipher-text data in an enc-val s-expression using PKCS#1 padding.
99 PAL::GCrypt::Handle<gcry_sexp_t> encValSexp;
100 gcry_error_t error = gcry_sexp_build(&encValSexp, nullptr, "(enc-val(flags pkcs1)(rsa(a %b)))",
101 cipherText.size(), cipherText.data());
102 if (error != GPG_ERR_NO_ERROR) {
103 PAL::GCrypt::logError(error);
104 return std::nullopt;
105 }
106
107 // Decrypt data with the provided key. The returned s-expression is of this form:
108 // (data
109 // (flags pkcs1)
110 // (value block))
111 PAL::GCrypt::Handle<gcry_sexp_t> plainSexp;
112 error = gcry_pk_decrypt(&plainSexp, encValSexp, keySexp);
113 if (error != GPG_ERR_NO_ERROR) {
114 PAL::GCrypt::logError(error);
115 return std::nullopt;
116 }
117
118 // Return MPI data of the embedded value integer.
119 PAL::GCrypt::Handle<gcry_sexp_t> valueSexp(gcry_sexp_find_token(plainSexp, "value", 0));
120 if (!valueSexp)
121 return std::nullopt;
122
123 return mpiData(valueSexp);
124}
125
126void CryptoAlgorithmRSAES_PKCS1_v1_5::platformEncrypt(Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
127{
128 context.ref();
129 workQueue.dispatch(
130 [key = WTFMove(key), plainText = WTFMove(plainText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
131 auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
132
133 auto output = gcryptEncrypt(rsaKey.platformKey(), WTFMove(plainText));
134 if (!output) {
135 // We should only dereference callbacks after being back to the Document/Worker threads.
136 context.postTask(
137 [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
138 exceptionCallback(OperationError);
139 context.deref();
140 });
141 return;
142 }
143
144 // We should only dereference callbacks after being back to the Document/Worker threads.
145 context.postTask(
146 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) mutable {
147 callback(WTFMove(output));
148 context.deref();
149 });
150 });
151}
152
153void CryptoAlgorithmRSAES_PKCS1_v1_5::platformDecrypt(Ref<CryptoKey>&& key, Vector<uint8_t>&& cipherText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
154{
155 context.ref();
156 workQueue.dispatch(
157 [key = WTFMove(key), cipherText = WTFMove(cipherText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
158 auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
159
160 auto output = gcryptDecrypt(rsaKey.platformKey(), WTFMove(cipherText));
161 if (!output) {
162 // We should only dereference callbacks after being back to the Document/Worker threads.
163 context.postTask(
164 [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
165 exceptionCallback(OperationError);
166 context.deref();
167 });
168 return;
169 }
170
171 // We should only dereference callbacks after being back to the Document/Worker threads.
172 context.postTask(
173 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) mutable {
174 callback(WTFMove(output));
175 context.deref();
176 });
177 });