xref: /aosp_15_r20/system/keymaster/cppcose/cppcose.cpp (revision 789431f29546679ab5188a97751fb38e3018d44d)
1*789431f2SAndroid Build Coastguard Worker /*
2*789431f2SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*789431f2SAndroid Build Coastguard Worker  *
4*789431f2SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*789431f2SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*789431f2SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*789431f2SAndroid Build Coastguard Worker  *
8*789431f2SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*789431f2SAndroid Build Coastguard Worker  *
10*789431f2SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*789431f2SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*789431f2SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*789431f2SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*789431f2SAndroid Build Coastguard Worker  * limitations under the License.
15*789431f2SAndroid Build Coastguard Worker  */
16*789431f2SAndroid Build Coastguard Worker 
17*789431f2SAndroid Build Coastguard Worker #include <keymaster/cppcose/cppcose.h>
18*789431f2SAndroid Build Coastguard Worker 
19*789431f2SAndroid Build Coastguard Worker #include <iostream>
20*789431f2SAndroid Build Coastguard Worker #include <stdio.h>
21*789431f2SAndroid Build Coastguard Worker 
22*789431f2SAndroid Build Coastguard Worker #include <cppbor.h>
23*789431f2SAndroid Build Coastguard Worker #include <cppbor_parse.h>
24*789431f2SAndroid Build Coastguard Worker #include <openssl/ecdsa.h>
25*789431f2SAndroid Build Coastguard Worker 
26*789431f2SAndroid Build Coastguard Worker #include <openssl/err.h>
27*789431f2SAndroid Build Coastguard Worker 
28*789431f2SAndroid Build Coastguard Worker namespace cppcose {
29*789431f2SAndroid Build Coastguard Worker constexpr int kP256AffinePointSize = 32;
30*789431f2SAndroid Build Coastguard Worker constexpr int kP384AffinePointSize = 48;
31*789431f2SAndroid Build Coastguard Worker 
32*789431f2SAndroid Build Coastguard Worker using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
33*789431f2SAndroid Build Coastguard Worker using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
34*789431f2SAndroid Build Coastguard Worker using ECDSA_SIG_Ptr = bssl::UniquePtr<ECDSA_SIG>;
35*789431f2SAndroid Build Coastguard Worker using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
36*789431f2SAndroid Build Coastguard Worker 
37*789431f2SAndroid Build Coastguard Worker namespace {
38*789431f2SAndroid Build Coastguard Worker 
aesGcmInitAndProcessAad(const bytevec & key,const bytevec & nonce,const bytevec & aad,bool encrypt)39*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key,
40*789431f2SAndroid Build Coastguard Worker                                                                   const bytevec& nonce,
41*789431f2SAndroid Build Coastguard Worker                                                                   const bytevec& aad,
42*789431f2SAndroid Build Coastguard Worker                                                                   bool encrypt) {
43*789431f2SAndroid Build Coastguard Worker     if (key.size() != kAesGcmKeySize) return "Invalid key size";
44*789431f2SAndroid Build Coastguard Worker 
45*789431f2SAndroid Build Coastguard Worker     bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
46*789431f2SAndroid Build Coastguard Worker     if (!ctx) return "Failed to allocate cipher context";
47*789431f2SAndroid Build Coastguard Worker 
48*789431f2SAndroid Build Coastguard Worker     if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(),
49*789431f2SAndroid Build Coastguard Worker                            nonce.data(), encrypt ? 1 : 0)) {
50*789431f2SAndroid Build Coastguard Worker         return "Failed to initialize cipher";
51*789431f2SAndroid Build Coastguard Worker     }
52*789431f2SAndroid Build Coastguard Worker 
53*789431f2SAndroid Build Coastguard Worker     int outlen;
54*789431f2SAndroid Build Coastguard Worker     if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen,
55*789431f2SAndroid Build Coastguard Worker                                           aad.data(), aad.size())) {
56*789431f2SAndroid Build Coastguard Worker         return "Failed to process AAD";
57*789431f2SAndroid Build Coastguard Worker     }
58*789431f2SAndroid Build Coastguard Worker 
59*789431f2SAndroid Build Coastguard Worker     return std::move(ctx);
60*789431f2SAndroid Build Coastguard Worker }
61*789431f2SAndroid Build Coastguard Worker 
signP256Digest(const bytevec & key,const bytevec & data)62*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> signP256Digest(const bytevec& key, const bytevec& data) {
63*789431f2SAndroid Build Coastguard Worker     auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr));
64*789431f2SAndroid Build Coastguard Worker     if (bn.get() == nullptr) {
65*789431f2SAndroid Build Coastguard Worker         return "Error creating BIGNUM";
66*789431f2SAndroid Build Coastguard Worker     }
67*789431f2SAndroid Build Coastguard Worker 
68*789431f2SAndroid Build Coastguard Worker     auto ec_key = EC_KEY_Ptr(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
69*789431f2SAndroid Build Coastguard Worker     if (EC_KEY_set_private_key(ec_key.get(), bn.get()) != 1) {
70*789431f2SAndroid Build Coastguard Worker         return "Error setting private key from BIGNUM";
71*789431f2SAndroid Build Coastguard Worker     }
72*789431f2SAndroid Build Coastguard Worker 
73*789431f2SAndroid Build Coastguard Worker     auto sig = ECDSA_SIG_Ptr(ECDSA_do_sign(data.data(), data.size(), ec_key.get()));
74*789431f2SAndroid Build Coastguard Worker     if (sig == nullptr) {
75*789431f2SAndroid Build Coastguard Worker         return "Error signing digest";
76*789431f2SAndroid Build Coastguard Worker     }
77*789431f2SAndroid Build Coastguard Worker     size_t len = i2d_ECDSA_SIG(sig.get(), nullptr);
78*789431f2SAndroid Build Coastguard Worker     bytevec signature(len);
79*789431f2SAndroid Build Coastguard Worker     unsigned char* p = (unsigned char*)signature.data();
80*789431f2SAndroid Build Coastguard Worker     i2d_ECDSA_SIG(sig.get(), &p);
81*789431f2SAndroid Build Coastguard Worker     return signature;
82*789431f2SAndroid Build Coastguard Worker }
83*789431f2SAndroid Build Coastguard Worker 
ecdh(const bytevec & publicKey,const bytevec & privateKey)84*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> ecdh(const bytevec& publicKey, const bytevec& privateKey) {
85*789431f2SAndroid Build Coastguard Worker     auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
86*789431f2SAndroid Build Coastguard Worker     auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
87*789431f2SAndroid Build Coastguard Worker     if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
88*789431f2SAndroid Build Coastguard Worker         1) {
89*789431f2SAndroid Build Coastguard Worker         return "Error decoding publicKey";
90*789431f2SAndroid Build Coastguard Worker     }
91*789431f2SAndroid Build Coastguard Worker     auto ecKey = EC_KEY_Ptr(EC_KEY_new());
92*789431f2SAndroid Build Coastguard Worker     auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
93*789431f2SAndroid Build Coastguard Worker     if (ecKey.get() == nullptr || pkey.get() == nullptr) {
94*789431f2SAndroid Build Coastguard Worker         return "Memory allocation failed";
95*789431f2SAndroid Build Coastguard Worker     }
96*789431f2SAndroid Build Coastguard Worker     if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
97*789431f2SAndroid Build Coastguard Worker         return "Error setting group";
98*789431f2SAndroid Build Coastguard Worker     }
99*789431f2SAndroid Build Coastguard Worker     if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
100*789431f2SAndroid Build Coastguard Worker         return "Error setting point";
101*789431f2SAndroid Build Coastguard Worker     }
102*789431f2SAndroid Build Coastguard Worker     if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
103*789431f2SAndroid Build Coastguard Worker         return "Error setting key";
104*789431f2SAndroid Build Coastguard Worker     }
105*789431f2SAndroid Build Coastguard Worker 
106*789431f2SAndroid Build Coastguard Worker     auto bn = BIGNUM_Ptr(BN_bin2bn(privateKey.data(), privateKey.size(), nullptr));
107*789431f2SAndroid Build Coastguard Worker     if (bn.get() == nullptr) {
108*789431f2SAndroid Build Coastguard Worker         return "Error creating BIGNUM for private key";
109*789431f2SAndroid Build Coastguard Worker     }
110*789431f2SAndroid Build Coastguard Worker     auto privEcKey = EC_KEY_Ptr(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
111*789431f2SAndroid Build Coastguard Worker     if (EC_KEY_set_private_key(privEcKey.get(), bn.get()) != 1) {
112*789431f2SAndroid Build Coastguard Worker         return "Error setting private key from BIGNUM";
113*789431f2SAndroid Build Coastguard Worker     }
114*789431f2SAndroid Build Coastguard Worker     auto privPkey = EVP_PKEY_Ptr(EVP_PKEY_new());
115*789431f2SAndroid Build Coastguard Worker     if (EVP_PKEY_set1_EC_KEY(privPkey.get(), privEcKey.get()) != 1) {
116*789431f2SAndroid Build Coastguard Worker         return "Error setting private key";
117*789431f2SAndroid Build Coastguard Worker     }
118*789431f2SAndroid Build Coastguard Worker 
119*789431f2SAndroid Build Coastguard Worker     auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(privPkey.get(), NULL));
120*789431f2SAndroid Build Coastguard Worker     if (ctx.get() == nullptr) {
121*789431f2SAndroid Build Coastguard Worker         return "Error creating context";
122*789431f2SAndroid Build Coastguard Worker     }
123*789431f2SAndroid Build Coastguard Worker 
124*789431f2SAndroid Build Coastguard Worker     if (EVP_PKEY_derive_init(ctx.get()) != 1) {
125*789431f2SAndroid Build Coastguard Worker         return "Error initializing context";
126*789431f2SAndroid Build Coastguard Worker     }
127*789431f2SAndroid Build Coastguard Worker 
128*789431f2SAndroid Build Coastguard Worker     if (EVP_PKEY_derive_set_peer(ctx.get(), pkey.get()) != 1) {
129*789431f2SAndroid Build Coastguard Worker         return "Error setting peer";
130*789431f2SAndroid Build Coastguard Worker     }
131*789431f2SAndroid Build Coastguard Worker 
132*789431f2SAndroid Build Coastguard Worker     /* Determine buffer length for shared secret */
133*789431f2SAndroid Build Coastguard Worker     size_t secretLen = 0;
134*789431f2SAndroid Build Coastguard Worker     if (EVP_PKEY_derive(ctx.get(), NULL, &secretLen) != 1) {
135*789431f2SAndroid Build Coastguard Worker         return "Error determing length of shared secret";
136*789431f2SAndroid Build Coastguard Worker     }
137*789431f2SAndroid Build Coastguard Worker     bytevec sharedSecret(secretLen);
138*789431f2SAndroid Build Coastguard Worker 
139*789431f2SAndroid Build Coastguard Worker     if (EVP_PKEY_derive(ctx.get(), sharedSecret.data(), &secretLen) != 1) {
140*789431f2SAndroid Build Coastguard Worker         return "Error deriving shared secret";
141*789431f2SAndroid Build Coastguard Worker     }
142*789431f2SAndroid Build Coastguard Worker     return sharedSecret;
143*789431f2SAndroid Build Coastguard Worker }
144*789431f2SAndroid Build Coastguard Worker 
ecdsaCoseSignatureToDer(int point_size,const bytevec & ecdsaCoseSignature)145*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> ecdsaCoseSignatureToDer(int point_size, const bytevec& ecdsaCoseSignature) {
146*789431f2SAndroid Build Coastguard Worker     if (ecdsaCoseSignature.size() != (size_t)(point_size * 2)) {
147*789431f2SAndroid Build Coastguard Worker         return "COSE signature wrong length";
148*789431f2SAndroid Build Coastguard Worker     }
149*789431f2SAndroid Build Coastguard Worker 
150*789431f2SAndroid Build Coastguard Worker     auto rBn = BIGNUM_Ptr(BN_bin2bn(ecdsaCoseSignature.data(), point_size, nullptr));
151*789431f2SAndroid Build Coastguard Worker     if (rBn.get() == nullptr) {
152*789431f2SAndroid Build Coastguard Worker         return "Error creating BIGNUM for r";
153*789431f2SAndroid Build Coastguard Worker     }
154*789431f2SAndroid Build Coastguard Worker 
155*789431f2SAndroid Build Coastguard Worker     auto sBn = BIGNUM_Ptr(BN_bin2bn(ecdsaCoseSignature.data() + point_size, point_size, nullptr));
156*789431f2SAndroid Build Coastguard Worker     if (sBn.get() == nullptr) {
157*789431f2SAndroid Build Coastguard Worker         return "Error creating BIGNUM for s";
158*789431f2SAndroid Build Coastguard Worker     }
159*789431f2SAndroid Build Coastguard Worker 
160*789431f2SAndroid Build Coastguard Worker     ECDSA_SIG sig;
161*789431f2SAndroid Build Coastguard Worker     sig.r = rBn.get();
162*789431f2SAndroid Build Coastguard Worker     sig.s = sBn.get();
163*789431f2SAndroid Build Coastguard Worker 
164*789431f2SAndroid Build Coastguard Worker     size_t len = i2d_ECDSA_SIG(&sig, nullptr);
165*789431f2SAndroid Build Coastguard Worker     bytevec derSignature(len);
166*789431f2SAndroid Build Coastguard Worker     unsigned char* p = (unsigned char*)derSignature.data();
167*789431f2SAndroid Build Coastguard Worker     i2d_ECDSA_SIG(&sig, &p);
168*789431f2SAndroid Build Coastguard Worker     return derSignature;
169*789431f2SAndroid Build Coastguard Worker }
170*789431f2SAndroid Build Coastguard Worker 
ecdsaDerSignatureToCose(int point_size,const bytevec & ecdsaSignature)171*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> ecdsaDerSignatureToCose(int point_size, const bytevec& ecdsaSignature) {
172*789431f2SAndroid Build Coastguard Worker     const unsigned char* p = ecdsaSignature.data();
173*789431f2SAndroid Build Coastguard Worker     auto sig = ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, ecdsaSignature.size()));
174*789431f2SAndroid Build Coastguard Worker     if (sig == nullptr) {
175*789431f2SAndroid Build Coastguard Worker         return "Error decoding DER signature";
176*789431f2SAndroid Build Coastguard Worker     }
177*789431f2SAndroid Build Coastguard Worker 
178*789431f2SAndroid Build Coastguard Worker     bytevec ecdsaCoseSignature(point_size * 2, 0);
179*789431f2SAndroid Build Coastguard Worker     if (BN_bn2binpad(ECDSA_SIG_get0_r(sig.get()), ecdsaCoseSignature.data(), point_size) !=
180*789431f2SAndroid Build Coastguard Worker         point_size) {
181*789431f2SAndroid Build Coastguard Worker         return "Error encoding r";
182*789431f2SAndroid Build Coastguard Worker     }
183*789431f2SAndroid Build Coastguard Worker     if (BN_bn2binpad(ECDSA_SIG_get0_s(sig.get()), ecdsaCoseSignature.data() + point_size,
184*789431f2SAndroid Build Coastguard Worker                      point_size) != point_size) {
185*789431f2SAndroid Build Coastguard Worker         return "Error encoding s";
186*789431f2SAndroid Build Coastguard Worker     }
187*789431f2SAndroid Build Coastguard Worker     return ecdsaCoseSignature;
188*789431f2SAndroid Build Coastguard Worker }
189*789431f2SAndroid Build Coastguard Worker 
verifyEcdsaDigest(int curve_nid,const bytevec & key,const bytevec & digest,const bytevec & signature)190*789431f2SAndroid Build Coastguard Worker bool verifyEcdsaDigest(int curve_nid, const bytevec& key, const bytevec& digest,
191*789431f2SAndroid Build Coastguard Worker                        const bytevec& signature) {
192*789431f2SAndroid Build Coastguard Worker     const unsigned char* p = (unsigned char*)signature.data();
193*789431f2SAndroid Build Coastguard Worker     auto sig = ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, signature.size()));
194*789431f2SAndroid Build Coastguard Worker     if (sig.get() == nullptr) {
195*789431f2SAndroid Build Coastguard Worker         return false;
196*789431f2SAndroid Build Coastguard Worker     }
197*789431f2SAndroid Build Coastguard Worker 
198*789431f2SAndroid Build Coastguard Worker     auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curve_nid));
199*789431f2SAndroid Build Coastguard Worker     auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
200*789431f2SAndroid Build Coastguard Worker     if (EC_POINT_oct2point(group.get(), point.get(), key.data(), key.size(), nullptr) != 1) {
201*789431f2SAndroid Build Coastguard Worker         return false;
202*789431f2SAndroid Build Coastguard Worker     }
203*789431f2SAndroid Build Coastguard Worker     auto ecKey = EC_KEY_Ptr(EC_KEY_new());
204*789431f2SAndroid Build Coastguard Worker     if (ecKey.get() == nullptr) {
205*789431f2SAndroid Build Coastguard Worker         return false;
206*789431f2SAndroid Build Coastguard Worker     }
207*789431f2SAndroid Build Coastguard Worker     if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
208*789431f2SAndroid Build Coastguard Worker         return false;
209*789431f2SAndroid Build Coastguard Worker     }
210*789431f2SAndroid Build Coastguard Worker     if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
211*789431f2SAndroid Build Coastguard Worker         return false;
212*789431f2SAndroid Build Coastguard Worker     }
213*789431f2SAndroid Build Coastguard Worker 
214*789431f2SAndroid Build Coastguard Worker     int rc = ECDSA_do_verify(digest.data(), digest.size(), sig.get(), ecKey.get());
215*789431f2SAndroid Build Coastguard Worker     if (rc != 1) {
216*789431f2SAndroid Build Coastguard Worker         return false;
217*789431f2SAndroid Build Coastguard Worker     }
218*789431f2SAndroid Build Coastguard Worker     return true;
219*789431f2SAndroid Build Coastguard Worker }
220*789431f2SAndroid Build Coastguard Worker 
221*789431f2SAndroid Build Coastguard Worker }  // namespace
222*789431f2SAndroid Build Coastguard Worker 
generateHmacSha256(const bytevec & key,const bytevec & data)223*789431f2SAndroid Build Coastguard Worker ErrMsgOr<HmacSha256> generateHmacSha256(const bytevec& key, const bytevec& data) {
224*789431f2SAndroid Build Coastguard Worker     HmacSha256 digest;
225*789431f2SAndroid Build Coastguard Worker     unsigned int outLen;
226*789431f2SAndroid Build Coastguard Worker     uint8_t* out = HMAC(EVP_sha256(),              //
227*789431f2SAndroid Build Coastguard Worker                         key.data(), key.size(),    //
228*789431f2SAndroid Build Coastguard Worker                         data.data(), data.size(),  //
229*789431f2SAndroid Build Coastguard Worker                         digest.data(), &outLen);
230*789431f2SAndroid Build Coastguard Worker 
231*789431f2SAndroid Build Coastguard Worker     if (out == nullptr || outLen != digest.size()) {
232*789431f2SAndroid Build Coastguard Worker         return "Error generating HMAC";
233*789431f2SAndroid Build Coastguard Worker     }
234*789431f2SAndroid Build Coastguard Worker     return digest;
235*789431f2SAndroid Build Coastguard Worker }
236*789431f2SAndroid Build Coastguard Worker 
generateCoseMac0Mac(HmacSha256Function macFunction,const bytevec & externalAad,const bytevec & payload)237*789431f2SAndroid Build Coastguard Worker ErrMsgOr<HmacSha256> generateCoseMac0Mac(HmacSha256Function macFunction, const bytevec& externalAad,
238*789431f2SAndroid Build Coastguard Worker                                          const bytevec& payload) {
239*789431f2SAndroid Build Coastguard Worker     auto macStructure = cppbor::Array()
240*789431f2SAndroid Build Coastguard Worker                             .add("MAC0")
241*789431f2SAndroid Build Coastguard Worker                             .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
242*789431f2SAndroid Build Coastguard Worker                             .add(externalAad)
243*789431f2SAndroid Build Coastguard Worker                             .add(payload)
244*789431f2SAndroid Build Coastguard Worker                             .encode();
245*789431f2SAndroid Build Coastguard Worker 
246*789431f2SAndroid Build Coastguard Worker     auto macTag = macFunction(macStructure);
247*789431f2SAndroid Build Coastguard Worker     if (!macTag) {
248*789431f2SAndroid Build Coastguard Worker         return "Error computing public key MAC";
249*789431f2SAndroid Build Coastguard Worker     }
250*789431f2SAndroid Build Coastguard Worker 
251*789431f2SAndroid Build Coastguard Worker     return *macTag;
252*789431f2SAndroid Build Coastguard Worker }
253*789431f2SAndroid Build Coastguard Worker 
constructCoseMac0(HmacSha256Function macFunction,const bytevec & externalAad,const bytevec & payload)254*789431f2SAndroid Build Coastguard Worker ErrMsgOr<cppbor::Array> constructCoseMac0(HmacSha256Function macFunction,
255*789431f2SAndroid Build Coastguard Worker                                           const bytevec& externalAad, const bytevec& payload) {
256*789431f2SAndroid Build Coastguard Worker     auto tag = generateCoseMac0Mac(macFunction, externalAad, payload);
257*789431f2SAndroid Build Coastguard Worker     if (!tag) return tag.moveMessage();
258*789431f2SAndroid Build Coastguard Worker 
259*789431f2SAndroid Build Coastguard Worker     return cppbor::Array()
260*789431f2SAndroid Build Coastguard Worker         .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
261*789431f2SAndroid Build Coastguard Worker         .add(cppbor::Map() /* unprotected */)
262*789431f2SAndroid Build Coastguard Worker         .add(payload)
263*789431f2SAndroid Build Coastguard Worker         .add(std::pair(tag->begin(), tag->end()));
264*789431f2SAndroid Build Coastguard Worker }
265*789431f2SAndroid Build Coastguard Worker 
verifyAndParseCoseMac0(const cppbor::Item * macItem,const bytevec & macKey)266*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
267*789431f2SAndroid Build Coastguard Worker                                                        const bytevec& macKey) {
268*789431f2SAndroid Build Coastguard Worker     auto mac = macItem ? macItem->asArray() : nullptr;
269*789431f2SAndroid Build Coastguard Worker     if (!mac || mac->size() != kCoseMac0EntryCount) {
270*789431f2SAndroid Build Coastguard Worker         return "Invalid COSE_Mac0";
271*789431f2SAndroid Build Coastguard Worker     }
272*789431f2SAndroid Build Coastguard Worker 
273*789431f2SAndroid Build Coastguard Worker     auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
274*789431f2SAndroid Build Coastguard Worker     auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap();
275*789431f2SAndroid Build Coastguard Worker     auto payload = mac->get(kCoseMac0Payload)->asBstr();
276*789431f2SAndroid Build Coastguard Worker     auto tag = mac->get(kCoseMac0Tag)->asBstr();
277*789431f2SAndroid Build Coastguard Worker     if (!protectedParms || !unprotectedParms || !payload || !tag) {
278*789431f2SAndroid Build Coastguard Worker         return "Invalid COSE_Mac0 contents";
279*789431f2SAndroid Build Coastguard Worker     }
280*789431f2SAndroid Build Coastguard Worker 
281*789431f2SAndroid Build Coastguard Worker     auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms);
282*789431f2SAndroid Build Coastguard Worker     if (!protectedMap || !protectedMap->asMap()) {
283*789431f2SAndroid Build Coastguard Worker         return "Invalid Mac0 protected: " + errMsg;
284*789431f2SAndroid Build Coastguard Worker     }
285*789431f2SAndroid Build Coastguard Worker     auto& algo = protectedMap->asMap()->get(ALGORITHM);
286*789431f2SAndroid Build Coastguard Worker     if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
287*789431f2SAndroid Build Coastguard Worker         return "Unsupported Mac0 algorithm";
288*789431f2SAndroid Build Coastguard Worker     }
289*789431f2SAndroid Build Coastguard Worker 
290*789431f2SAndroid Build Coastguard Worker     auto macFunction = [&macKey](const bytevec& input) {
291*789431f2SAndroid Build Coastguard Worker         return generateHmacSha256(macKey, input);
292*789431f2SAndroid Build Coastguard Worker     };
293*789431f2SAndroid Build Coastguard Worker     auto macTag = generateCoseMac0Mac(macFunction, {} /* external_aad */, payload->value());
294*789431f2SAndroid Build Coastguard Worker     if (!macTag) return macTag.moveMessage();
295*789431f2SAndroid Build Coastguard Worker 
296*789431f2SAndroid Build Coastguard Worker     if (macTag->size() != tag->value().size() ||
297*789431f2SAndroid Build Coastguard Worker         CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
298*789431f2SAndroid Build Coastguard Worker         return "MAC tag mismatch";
299*789431f2SAndroid Build Coastguard Worker     }
300*789431f2SAndroid Build Coastguard Worker 
301*789431f2SAndroid Build Coastguard Worker     return payload->value();
302*789431f2SAndroid Build Coastguard Worker }
303*789431f2SAndroid Build Coastguard Worker 
createECDSACoseSign1Signature(const bytevec & key,const bytevec & protectedParams,const bytevec & payload,const bytevec & aad)304*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> createECDSACoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
305*789431f2SAndroid Build Coastguard Worker                                                 const bytevec& payload, const bytevec& aad) {
306*789431f2SAndroid Build Coastguard Worker     bytevec signatureInput = cppbor::Array()
307*789431f2SAndroid Build Coastguard Worker                                  .add("Signature1")  //
308*789431f2SAndroid Build Coastguard Worker                                  .add(protectedParams)
309*789431f2SAndroid Build Coastguard Worker                                  .add(aad)
310*789431f2SAndroid Build Coastguard Worker                                  .add(payload)
311*789431f2SAndroid Build Coastguard Worker                                  .encode();
312*789431f2SAndroid Build Coastguard Worker     auto ecdsaSignature = signP256Digest(key, sha256(signatureInput));
313*789431f2SAndroid Build Coastguard Worker     if (!ecdsaSignature) return ecdsaSignature.moveMessage();
314*789431f2SAndroid Build Coastguard Worker 
315*789431f2SAndroid Build Coastguard Worker     return ecdsaDerSignatureToCose(kP256AffinePointSize, *ecdsaSignature);
316*789431f2SAndroid Build Coastguard Worker }
317*789431f2SAndroid Build Coastguard Worker 
createCoseSign1Signature(const bytevec & key,const bytevec & protectedParams,const bytevec & payload,const bytevec & aad)318*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
319*789431f2SAndroid Build Coastguard Worker                                            const bytevec& payload, const bytevec& aad) {
320*789431f2SAndroid Build Coastguard Worker     bytevec signatureInput = cppbor::Array()
321*789431f2SAndroid Build Coastguard Worker                                  .add("Signature1")  //
322*789431f2SAndroid Build Coastguard Worker                                  .add(protectedParams)
323*789431f2SAndroid Build Coastguard Worker                                  .add(aad)
324*789431f2SAndroid Build Coastguard Worker                                  .add(payload)
325*789431f2SAndroid Build Coastguard Worker                                  .encode();
326*789431f2SAndroid Build Coastguard Worker 
327*789431f2SAndroid Build Coastguard Worker     if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key";
328*789431f2SAndroid Build Coastguard Worker     bytevec signature(ED25519_SIGNATURE_LEN);
329*789431f2SAndroid Build Coastguard Worker     if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) {
330*789431f2SAndroid Build Coastguard Worker         return "Signing failed";
331*789431f2SAndroid Build Coastguard Worker     }
332*789431f2SAndroid Build Coastguard Worker 
333*789431f2SAndroid Build Coastguard Worker     return signature;
334*789431f2SAndroid Build Coastguard Worker }
335*789431f2SAndroid Build Coastguard Worker 
constructECDSACoseSign1(const bytevec & key,cppbor::Map protectedParams,const bytevec & payload,const bytevec & aad)336*789431f2SAndroid Build Coastguard Worker ErrMsgOr<cppbor::Array> constructECDSACoseSign1(const bytevec& key, cppbor::Map protectedParams,
337*789431f2SAndroid Build Coastguard Worker                                                 const bytevec& payload, const bytevec& aad) {
338*789431f2SAndroid Build Coastguard Worker     bytevec protParms = protectedParams.add(ALGORITHM, ES256).canonicalize().encode();
339*789431f2SAndroid Build Coastguard Worker     auto signature = createECDSACoseSign1Signature(key, protParms, payload, aad);
340*789431f2SAndroid Build Coastguard Worker     if (!signature) return signature.moveMessage();
341*789431f2SAndroid Build Coastguard Worker 
342*789431f2SAndroid Build Coastguard Worker     return cppbor::Array()
343*789431f2SAndroid Build Coastguard Worker         .add(std::move(protParms))
344*789431f2SAndroid Build Coastguard Worker         .add(cppbor::Map() /* unprotected parameters */)
345*789431f2SAndroid Build Coastguard Worker         .add(std::move(payload))
346*789431f2SAndroid Build Coastguard Worker         .add(std::move(*signature));
347*789431f2SAndroid Build Coastguard Worker }
348*789431f2SAndroid Build Coastguard Worker 
constructCoseSign1(const bytevec & key,cppbor::Map protectedParams,const bytevec & payload,const bytevec & aad)349*789431f2SAndroid Build Coastguard Worker ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
350*789431f2SAndroid Build Coastguard Worker                                            const bytevec& payload, const bytevec& aad) {
351*789431f2SAndroid Build Coastguard Worker     bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
352*789431f2SAndroid Build Coastguard Worker     auto signature = createCoseSign1Signature(key, protParms, payload, aad);
353*789431f2SAndroid Build Coastguard Worker     if (!signature) return signature.moveMessage();
354*789431f2SAndroid Build Coastguard Worker 
355*789431f2SAndroid Build Coastguard Worker     return cppbor::Array()
356*789431f2SAndroid Build Coastguard Worker         .add(std::move(protParms))
357*789431f2SAndroid Build Coastguard Worker         .add(cppbor::Map() /* unprotected parameters */)
358*789431f2SAndroid Build Coastguard Worker         .add(std::move(payload))
359*789431f2SAndroid Build Coastguard Worker         .add(std::move(*signature));
360*789431f2SAndroid Build Coastguard Worker }
361*789431f2SAndroid Build Coastguard Worker 
constructCoseSign1(const bytevec & key,const bytevec & payload,const bytevec & aad)362*789431f2SAndroid Build Coastguard Worker ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
363*789431f2SAndroid Build Coastguard Worker                                            const bytevec& aad) {
364*789431f2SAndroid Build Coastguard Worker     return constructCoseSign1(key, {} /* protectedParams */, payload, aad);
365*789431f2SAndroid Build Coastguard Worker }
366*789431f2SAndroid Build Coastguard Worker 
verifyAndParseCoseSign1(const cppbor::Array * coseSign1,const bytevec & signingCoseKey,const bytevec & aad)367*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
368*789431f2SAndroid Build Coastguard Worker                                           const bytevec& signingCoseKey, const bytevec& aad) {
369*789431f2SAndroid Build Coastguard Worker     if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
370*789431f2SAndroid Build Coastguard Worker         return "Invalid COSE_Sign1";
371*789431f2SAndroid Build Coastguard Worker     }
372*789431f2SAndroid Build Coastguard Worker 
373*789431f2SAndroid Build Coastguard Worker     const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
374*789431f2SAndroid Build Coastguard Worker     const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
375*789431f2SAndroid Build Coastguard Worker     const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
376*789431f2SAndroid Build Coastguard Worker 
377*789431f2SAndroid Build Coastguard Worker     if (!protectedParams || !unprotectedParams || !payload) {
378*789431f2SAndroid Build Coastguard Worker         return "Missing input parameters";
379*789431f2SAndroid Build Coastguard Worker     }
380*789431f2SAndroid Build Coastguard Worker 
381*789431f2SAndroid Build Coastguard Worker     auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
382*789431f2SAndroid Build Coastguard Worker     if (!parsedProtParams) {
383*789431f2SAndroid Build Coastguard Worker         return errMsg + " when parsing protected params.";
384*789431f2SAndroid Build Coastguard Worker     }
385*789431f2SAndroid Build Coastguard Worker     if (!parsedProtParams->asMap()) {
386*789431f2SAndroid Build Coastguard Worker         return "Protected params must be a map";
387*789431f2SAndroid Build Coastguard Worker     }
388*789431f2SAndroid Build Coastguard Worker 
389*789431f2SAndroid Build Coastguard Worker     auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
390*789431f2SAndroid Build Coastguard Worker     if (!algorithm || !algorithm->asInt() ||
391*789431f2SAndroid Build Coastguard Worker         !(algorithm->asInt()->value() == EDDSA || algorithm->asInt()->value() == ES256 ||
392*789431f2SAndroid Build Coastguard Worker           algorithm->asInt()->value() == ES384)) {
393*789431f2SAndroid Build Coastguard Worker         return "Unsupported signature algorithm";
394*789431f2SAndroid Build Coastguard Worker     }
395*789431f2SAndroid Build Coastguard Worker 
396*789431f2SAndroid Build Coastguard Worker     const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
397*789431f2SAndroid Build Coastguard Worker     if (!signature || signature->value().empty()) {
398*789431f2SAndroid Build Coastguard Worker         return "Missing signature input";
399*789431f2SAndroid Build Coastguard Worker     }
400*789431f2SAndroid Build Coastguard Worker 
401*789431f2SAndroid Build Coastguard Worker     bool selfSigned = signingCoseKey.empty();
402*789431f2SAndroid Build Coastguard Worker     bytevec signatureInput =
403*789431f2SAndroid Build Coastguard Worker         cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
404*789431f2SAndroid Build Coastguard Worker     if (algorithm->asInt()->value() == EDDSA) {
405*789431f2SAndroid Build Coastguard Worker         auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
406*789431f2SAndroid Build Coastguard Worker         if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty()) {
407*789431f2SAndroid Build Coastguard Worker             return "Bad signing key: " + key.moveMessage();
408*789431f2SAndroid Build Coastguard Worker         }
409*789431f2SAndroid Build Coastguard Worker 
410*789431f2SAndroid Build Coastguard Worker         if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
411*789431f2SAndroid Build Coastguard Worker                             key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
412*789431f2SAndroid Build Coastguard Worker             return "Signature verification failed";
413*789431f2SAndroid Build Coastguard Worker         }
414*789431f2SAndroid Build Coastguard Worker     } else if (algorithm->asInt()->value() == ES256) {
415*789431f2SAndroid Build Coastguard Worker         auto key = CoseKey::parseP256(selfSigned ? payload->value() : signingCoseKey);
416*789431f2SAndroid Build Coastguard Worker         if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
417*789431f2SAndroid Build Coastguard Worker             key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
418*789431f2SAndroid Build Coastguard Worker             return "Bad signing key: " + key.moveMessage();
419*789431f2SAndroid Build Coastguard Worker         }
420*789431f2SAndroid Build Coastguard Worker         auto publicKey = key->getEcPublicKey();
421*789431f2SAndroid Build Coastguard Worker         if (!publicKey) return publicKey.moveMessage();
422*789431f2SAndroid Build Coastguard Worker 
423*789431f2SAndroid Build Coastguard Worker         auto ecdsaDerSignature = ecdsaCoseSignatureToDer(kP256AffinePointSize, signature->value());
424*789431f2SAndroid Build Coastguard Worker         if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();
425*789431f2SAndroid Build Coastguard Worker 
426*789431f2SAndroid Build Coastguard Worker         // convert public key to uncompressed form by prepending 0x04 at begin.
427*789431f2SAndroid Build Coastguard Worker         publicKey->insert(publicKey->begin(), 0x04);
428*789431f2SAndroid Build Coastguard Worker 
429*789431f2SAndroid Build Coastguard Worker         if (!verifyEcdsaDigest(NID_X9_62_prime256v1, publicKey.moveValue(), sha256(signatureInput),
430*789431f2SAndroid Build Coastguard Worker                                *ecdsaDerSignature)) {
431*789431f2SAndroid Build Coastguard Worker             return "Signature verification failed";
432*789431f2SAndroid Build Coastguard Worker         }
433*789431f2SAndroid Build Coastguard Worker     } else {  // ES384
434*789431f2SAndroid Build Coastguard Worker         auto key = CoseKey::parseP384(selfSigned ? payload->value() : signingCoseKey);
435*789431f2SAndroid Build Coastguard Worker         if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
436*789431f2SAndroid Build Coastguard Worker             key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
437*789431f2SAndroid Build Coastguard Worker             return "Bad signing key: " + key.moveMessage();
438*789431f2SAndroid Build Coastguard Worker         }
439*789431f2SAndroid Build Coastguard Worker         auto publicKey = key->getEcPublicKey();
440*789431f2SAndroid Build Coastguard Worker         if (!publicKey) return publicKey.moveMessage();
441*789431f2SAndroid Build Coastguard Worker 
442*789431f2SAndroid Build Coastguard Worker         auto ecdsaDerSignature = ecdsaCoseSignatureToDer(kP384AffinePointSize, signature->value());
443*789431f2SAndroid Build Coastguard Worker         if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();
444*789431f2SAndroid Build Coastguard Worker 
445*789431f2SAndroid Build Coastguard Worker         // convert public key to uncompressed form by prepending 0x04 at begin.
446*789431f2SAndroid Build Coastguard Worker         publicKey->insert(publicKey->begin(), 0x04);
447*789431f2SAndroid Build Coastguard Worker 
448*789431f2SAndroid Build Coastguard Worker         if (!verifyEcdsaDigest(NID_secp384r1, publicKey.moveValue(), sha384(signatureInput),
449*789431f2SAndroid Build Coastguard Worker                                *ecdsaDerSignature)) {
450*789431f2SAndroid Build Coastguard Worker             return "Signature verification failed";
451*789431f2SAndroid Build Coastguard Worker         }
452*789431f2SAndroid Build Coastguard Worker     }
453*789431f2SAndroid Build Coastguard Worker 
454*789431f2SAndroid Build Coastguard Worker     return payload->value();
455*789431f2SAndroid Build Coastguard Worker }
456*789431f2SAndroid Build Coastguard Worker 
createCoseEncryptCiphertext(const bytevec & key,const bytevec & nonce,const bytevec & protectedParams,const bytevec & plaintextPayload,const bytevec & aad)457*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
458*789431f2SAndroid Build Coastguard Worker                                               const bytevec& protectedParams,
459*789431f2SAndroid Build Coastguard Worker                                               const bytevec& plaintextPayload, const bytevec& aad) {
460*789431f2SAndroid Build Coastguard Worker     auto ciphertext = aesGcmEncrypt(key, nonce,
461*789431f2SAndroid Build Coastguard Worker                                     cppbor::Array()            // Enc strucure as AAD
462*789431f2SAndroid Build Coastguard Worker                                         .add("Encrypt")        // Context
463*789431f2SAndroid Build Coastguard Worker                                         .add(protectedParams)  // Protected
464*789431f2SAndroid Build Coastguard Worker                                         .add(aad)              // External AAD
465*789431f2SAndroid Build Coastguard Worker                                         .encode(),
466*789431f2SAndroid Build Coastguard Worker                                     plaintextPayload);
467*789431f2SAndroid Build Coastguard Worker 
468*789431f2SAndroid Build Coastguard Worker     if (!ciphertext) return ciphertext.moveMessage();
469*789431f2SAndroid Build Coastguard Worker     return ciphertext.moveValue();
470*789431f2SAndroid Build Coastguard Worker }
471*789431f2SAndroid Build Coastguard Worker 
constructCoseEncrypt(const bytevec & key,const bytevec & nonce,const bytevec & plaintextPayload,const bytevec & aad,cppbor::Array recipients)472*789431f2SAndroid Build Coastguard Worker ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
473*789431f2SAndroid Build Coastguard Worker                                              const bytevec& plaintextPayload, const bytevec& aad,
474*789431f2SAndroid Build Coastguard Worker                                              cppbor::Array recipients) {
475*789431f2SAndroid Build Coastguard Worker     auto encryptProtectedHeader = cppbor::Map()  //
476*789431f2SAndroid Build Coastguard Worker                                       .add(ALGORITHM, AES_GCM_256)
477*789431f2SAndroid Build Coastguard Worker                                       .canonicalize()
478*789431f2SAndroid Build Coastguard Worker                                       .encode();
479*789431f2SAndroid Build Coastguard Worker 
480*789431f2SAndroid Build Coastguard Worker     auto ciphertext =
481*789431f2SAndroid Build Coastguard Worker         createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad);
482*789431f2SAndroid Build Coastguard Worker     if (!ciphertext) return ciphertext.moveMessage();
483*789431f2SAndroid Build Coastguard Worker 
484*789431f2SAndroid Build Coastguard Worker     return cppbor::Array()
485*789431f2SAndroid Build Coastguard Worker         .add(encryptProtectedHeader)                       // Protected
486*789431f2SAndroid Build Coastguard Worker         .add(cppbor::Map().add(IV, nonce).canonicalize())  // Unprotected
487*789431f2SAndroid Build Coastguard Worker         .add(*ciphertext)                                  // Payload
488*789431f2SAndroid Build Coastguard Worker         .add(std::move(recipients));
489*789431f2SAndroid Build Coastguard Worker }
490*789431f2SAndroid Build Coastguard Worker 
491*789431f2SAndroid Build Coastguard Worker ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
getSenderPubKeyFromCoseEncrypt(const cppbor::Item * coseEncrypt)492*789431f2SAndroid Build Coastguard Worker getSenderPubKeyFromCoseEncrypt(const cppbor::Item* coseEncrypt) {
493*789431f2SAndroid Build Coastguard Worker     if (!coseEncrypt || !coseEncrypt->asArray() ||
494*789431f2SAndroid Build Coastguard Worker         coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
495*789431f2SAndroid Build Coastguard Worker         return "Invalid COSE_Encrypt";
496*789431f2SAndroid Build Coastguard Worker     }
497*789431f2SAndroid Build Coastguard Worker 
498*789431f2SAndroid Build Coastguard Worker     auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
499*789431f2SAndroid Build Coastguard Worker     if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) {
500*789431f2SAndroid Build Coastguard Worker         return "Invalid recipients list";
501*789431f2SAndroid Build Coastguard Worker     }
502*789431f2SAndroid Build Coastguard Worker 
503*789431f2SAndroid Build Coastguard Worker     auto& recipient = recipients->asArray()->get(0);
504*789431f2SAndroid Build Coastguard Worker     if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) {
505*789431f2SAndroid Build Coastguard Worker         return "Invalid COSE_recipient";
506*789431f2SAndroid Build Coastguard Worker     }
507*789431f2SAndroid Build Coastguard Worker 
508*789431f2SAndroid Build Coastguard Worker     auto& ciphertext = recipient->asArray()->get(2);
509*789431f2SAndroid Build Coastguard Worker     if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) {
510*789431f2SAndroid Build Coastguard Worker         return "Unexpected value in recipients ciphertext field " +
511*789431f2SAndroid Build Coastguard Worker                cppbor::prettyPrint(ciphertext.get());
512*789431f2SAndroid Build Coastguard Worker     }
513*789431f2SAndroid Build Coastguard Worker 
514*789431f2SAndroid Build Coastguard Worker     auto& protParms = recipient->asArray()->get(0);
515*789431f2SAndroid Build Coastguard Worker     if (!protParms || !protParms->asBstr()) return "Invalid protected params";
516*789431f2SAndroid Build Coastguard Worker     auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr());
517*789431f2SAndroid Build Coastguard Worker     if (!parsedProtParms) return "Failed to parse protected params: " + errMsg;
518*789431f2SAndroid Build Coastguard Worker     if (!parsedProtParms->asMap()) return "Invalid protected params";
519*789431f2SAndroid Build Coastguard Worker 
520*789431f2SAndroid Build Coastguard Worker     auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM);
521*789431f2SAndroid Build Coastguard Worker     if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) {
522*789431f2SAndroid Build Coastguard Worker         return "Invalid algorithm";
523*789431f2SAndroid Build Coastguard Worker     }
524*789431f2SAndroid Build Coastguard Worker 
525*789431f2SAndroid Build Coastguard Worker     auto& unprotParms = recipient->asArray()->get(1);
526*789431f2SAndroid Build Coastguard Worker     if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params";
527*789431f2SAndroid Build Coastguard Worker 
528*789431f2SAndroid Build Coastguard Worker     auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY);
529*789431f2SAndroid Build Coastguard Worker     if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
530*789431f2SAndroid Build Coastguard Worker 
531*789431f2SAndroid Build Coastguard Worker     auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
532*789431f2SAndroid Build Coastguard Worker     if (!keyType || !keyType->asInt() ||
533*789431f2SAndroid Build Coastguard Worker         (keyType->asInt()->value() != OCTET_KEY_PAIR && keyType->asInt()->value() != EC2)) {
534*789431f2SAndroid Build Coastguard Worker         return "Invalid key type";
535*789431f2SAndroid Build Coastguard Worker     }
536*789431f2SAndroid Build Coastguard Worker 
537*789431f2SAndroid Build Coastguard Worker     auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
538*789431f2SAndroid Build Coastguard Worker     if (!curve || !curve->asInt() ||
539*789431f2SAndroid Build Coastguard Worker         (keyType->asInt()->value() == OCTET_KEY_PAIR && curve->asInt()->value() != X25519) ||
540*789431f2SAndroid Build Coastguard Worker         (keyType->asInt()->value() == EC2 && curve->asInt()->value() != P256)) {
541*789431f2SAndroid Build Coastguard Worker         return "Unsupported curve";
542*789431f2SAndroid Build Coastguard Worker     }
543*789431f2SAndroid Build Coastguard Worker 
544*789431f2SAndroid Build Coastguard Worker     bytevec publicKey;
545*789431f2SAndroid Build Coastguard Worker     if (keyType->asInt()->value() == EC2) {
546*789431f2SAndroid Build Coastguard Worker         auto& pubX = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
547*789431f2SAndroid Build Coastguard Worker         if (!pubX || !pubX->asBstr() || pubX->asBstr()->value().size() != kP256AffinePointSize) {
548*789431f2SAndroid Build Coastguard Worker             return "Invalid EC public key";
549*789431f2SAndroid Build Coastguard Worker         }
550*789431f2SAndroid Build Coastguard Worker         auto& pubY = senderCoseKey->asMap()->get(CoseKey::PUBKEY_Y);
551*789431f2SAndroid Build Coastguard Worker         if (!pubY || !pubY->asBstr() || pubY->asBstr()->value().size() != kP256AffinePointSize) {
552*789431f2SAndroid Build Coastguard Worker             return "Invalid EC public key";
553*789431f2SAndroid Build Coastguard Worker         }
554*789431f2SAndroid Build Coastguard Worker         auto key = CoseKey::getEcPublicKey(pubX->asBstr()->value(), pubY->asBstr()->value());
555*789431f2SAndroid Build Coastguard Worker         if (!key) return key.moveMessage();
556*789431f2SAndroid Build Coastguard Worker         publicKey = key.moveValue();
557*789431f2SAndroid Build Coastguard Worker     } else {
558*789431f2SAndroid Build Coastguard Worker         auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
559*789431f2SAndroid Build Coastguard Worker         if (!pubkey || !pubkey->asBstr() ||
560*789431f2SAndroid Build Coastguard Worker             pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
561*789431f2SAndroid Build Coastguard Worker             return "Invalid X25519 public key";
562*789431f2SAndroid Build Coastguard Worker         }
563*789431f2SAndroid Build Coastguard Worker         publicKey = pubkey->asBstr()->value();
564*789431f2SAndroid Build Coastguard Worker     }
565*789431f2SAndroid Build Coastguard Worker 
566*789431f2SAndroid Build Coastguard Worker     auto& key_id = unprotParms->asMap()->get(KEY_ID);
567*789431f2SAndroid Build Coastguard Worker     if (key_id && key_id->asBstr()) {
568*789431f2SAndroid Build Coastguard Worker         return std::make_pair(publicKey, key_id->asBstr()->value());
569*789431f2SAndroid Build Coastguard Worker     }
570*789431f2SAndroid Build Coastguard Worker 
571*789431f2SAndroid Build Coastguard Worker     // If no key ID, just return an empty vector.
572*789431f2SAndroid Build Coastguard Worker     return std::make_pair(publicKey, bytevec{});
573*789431f2SAndroid Build Coastguard Worker }
574*789431f2SAndroid Build Coastguard Worker 
decryptCoseEncrypt(const bytevec & key,const cppbor::Item * coseEncrypt,const bytevec & external_aad)575*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
576*789431f2SAndroid Build Coastguard Worker                                      const bytevec& external_aad) {
577*789431f2SAndroid Build Coastguard Worker     if (!coseEncrypt || !coseEncrypt->asArray() ||
578*789431f2SAndroid Build Coastguard Worker         coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
579*789431f2SAndroid Build Coastguard Worker         return "Invalid COSE_Encrypt";
580*789431f2SAndroid Build Coastguard Worker     }
581*789431f2SAndroid Build Coastguard Worker 
582*789431f2SAndroid Build Coastguard Worker     auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams);
583*789431f2SAndroid Build Coastguard Worker     auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams);
584*789431f2SAndroid Build Coastguard Worker     auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload);
585*789431f2SAndroid Build Coastguard Worker     auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
586*789431f2SAndroid Build Coastguard Worker 
587*789431f2SAndroid Build Coastguard Worker     if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) {
588*789431f2SAndroid Build Coastguard Worker         return "Invalid COSE_Encrypt";
589*789431f2SAndroid Build Coastguard Worker     }
590*789431f2SAndroid Build Coastguard Worker 
591*789431f2SAndroid Build Coastguard Worker     auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value());
592*789431f2SAndroid Build Coastguard Worker     if (!parsedProtParams) {
593*789431f2SAndroid Build Coastguard Worker         return errMsg + " when parsing protected params.";
594*789431f2SAndroid Build Coastguard Worker     }
595*789431f2SAndroid Build Coastguard Worker     if (!parsedProtParams->asMap()) {
596*789431f2SAndroid Build Coastguard Worker         return "Protected params must be a map";
597*789431f2SAndroid Build Coastguard Worker     }
598*789431f2SAndroid Build Coastguard Worker 
599*789431f2SAndroid Build Coastguard Worker     auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
600*789431f2SAndroid Build Coastguard Worker     if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) {
601*789431f2SAndroid Build Coastguard Worker         return "Unsupported encryption algorithm";
602*789431f2SAndroid Build Coastguard Worker     }
603*789431f2SAndroid Build Coastguard Worker 
604*789431f2SAndroid Build Coastguard Worker     if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) {
605*789431f2SAndroid Build Coastguard Worker         return "Invalid unprotected params";
606*789431f2SAndroid Build Coastguard Worker     }
607*789431f2SAndroid Build Coastguard Worker 
608*789431f2SAndroid Build Coastguard Worker     auto& nonce = unprotParms->asMap()->get(IV);
609*789431f2SAndroid Build Coastguard Worker     if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) {
610*789431f2SAndroid Build Coastguard Worker         return "Invalid nonce";
611*789431f2SAndroid Build Coastguard Worker     }
612*789431f2SAndroid Build Coastguard Worker 
613*789431f2SAndroid Build Coastguard Worker     if (!ciphertext->asBstr()) return "Invalid ciphertext";
614*789431f2SAndroid Build Coastguard Worker 
615*789431f2SAndroid Build Coastguard Worker     auto aad = cppbor::Array()                         // Enc strucure as AAD
616*789431f2SAndroid Build Coastguard Worker                    .add("Encrypt")                     // Context
617*789431f2SAndroid Build Coastguard Worker                    .add(protParms->asBstr()->value())  // Protected
618*789431f2SAndroid Build Coastguard Worker                    .add(external_aad)                  // External AAD
619*789431f2SAndroid Build Coastguard Worker                    .encode();
620*789431f2SAndroid Build Coastguard Worker 
621*789431f2SAndroid Build Coastguard Worker     return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
622*789431f2SAndroid Build Coastguard Worker }
623*789431f2SAndroid Build Coastguard Worker 
consructKdfContext(const bytevec & pubKeyA,const bytevec & privKeyA,const bytevec & pubKeyB,bool senderIsA)624*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> consructKdfContext(const bytevec& pubKeyA, const bytevec& privKeyA,
625*789431f2SAndroid Build Coastguard Worker                                      const bytevec& pubKeyB, bool senderIsA) {
626*789431f2SAndroid Build Coastguard Worker     if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) {
627*789431f2SAndroid Build Coastguard Worker         return "Missing input key parameters";
628*789431f2SAndroid Build Coastguard Worker     }
629*789431f2SAndroid Build Coastguard Worker 
630*789431f2SAndroid Build Coastguard Worker     bytevec kdfContext = cppbor::Array()
631*789431f2SAndroid Build Coastguard Worker                              .add(AES_GCM_256)
632*789431f2SAndroid Build Coastguard Worker                              .add(cppbor::Array()  // Sender Info
633*789431f2SAndroid Build Coastguard Worker                                       .add(cppbor::Bstr("client"))
634*789431f2SAndroid Build Coastguard Worker                                       .add(bytevec{} /* nonce */)
635*789431f2SAndroid Build Coastguard Worker                                       .add(senderIsA ? pubKeyA : pubKeyB))
636*789431f2SAndroid Build Coastguard Worker                              .add(cppbor::Array()  // Recipient Info
637*789431f2SAndroid Build Coastguard Worker                                       .add(cppbor::Bstr("server"))
638*789431f2SAndroid Build Coastguard Worker                                       .add(bytevec{} /* nonce */)
639*789431f2SAndroid Build Coastguard Worker                                       .add(senderIsA ? pubKeyB : pubKeyA))
640*789431f2SAndroid Build Coastguard Worker                              .add(cppbor::Array()               // SuppPubInfo
641*789431f2SAndroid Build Coastguard Worker                                       .add(kAesGcmKeySizeBits)  // output key length
642*789431f2SAndroid Build Coastguard Worker                                       .add(bytevec{}))          // protected
643*789431f2SAndroid Build Coastguard Worker                              .encode();
644*789431f2SAndroid Build Coastguard Worker     return kdfContext;
645*789431f2SAndroid Build Coastguard Worker }
646*789431f2SAndroid Build Coastguard Worker 
ECDH_HKDF_DeriveKey(const bytevec & pubKeyA,const bytevec & privKeyA,const bytevec & pubKeyB,bool senderIsA)647*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
648*789431f2SAndroid Build Coastguard Worker                                       const bytevec& pubKeyB, bool senderIsA) {
649*789431f2SAndroid Build Coastguard Worker     if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) {
650*789431f2SAndroid Build Coastguard Worker         return "Missing input key parameters";
651*789431f2SAndroid Build Coastguard Worker     }
652*789431f2SAndroid Build Coastguard Worker 
653*789431f2SAndroid Build Coastguard Worker     // convert public key to uncompressed form by prepending 0x04 at begin
654*789431f2SAndroid Build Coastguard Worker     bytevec publicKey;
655*789431f2SAndroid Build Coastguard Worker     publicKey.insert(publicKey.begin(), 0x04);
656*789431f2SAndroid Build Coastguard Worker     publicKey.insert(publicKey.end(), pubKeyB.begin(), pubKeyB.end());
657*789431f2SAndroid Build Coastguard Worker     auto rawSharedKey = ecdh(publicKey, privKeyA);
658*789431f2SAndroid Build Coastguard Worker     if (!rawSharedKey) return rawSharedKey.moveMessage();
659*789431f2SAndroid Build Coastguard Worker 
660*789431f2SAndroid Build Coastguard Worker     auto kdfContext = consructKdfContext(pubKeyA, privKeyA, pubKeyB, senderIsA);
661*789431f2SAndroid Build Coastguard Worker     if (!kdfContext) return kdfContext.moveMessage();
662*789431f2SAndroid Build Coastguard Worker 
663*789431f2SAndroid Build Coastguard Worker     bytevec retval(SHA256_DIGEST_LENGTH);
664*789431f2SAndroid Build Coastguard Worker     bytevec salt{};
665*789431f2SAndroid Build Coastguard Worker     if (!HKDF(retval.data(), retval.size(),                //
666*789431f2SAndroid Build Coastguard Worker               EVP_sha256(),                                //
667*789431f2SAndroid Build Coastguard Worker               rawSharedKey->data(), rawSharedKey->size(),  //
668*789431f2SAndroid Build Coastguard Worker               salt.data(), salt.size(),                    //
669*789431f2SAndroid Build Coastguard Worker               kdfContext->data(), kdfContext->size())) {
670*789431f2SAndroid Build Coastguard Worker         return "ECDH HKDF failed";
671*789431f2SAndroid Build Coastguard Worker     }
672*789431f2SAndroid Build Coastguard Worker 
673*789431f2SAndroid Build Coastguard Worker     return retval;
674*789431f2SAndroid Build Coastguard Worker }
675*789431f2SAndroid Build Coastguard Worker 
x25519_HKDF_DeriveKey(const bytevec & pubKeyA,const bytevec & privKeyA,const bytevec & pubKeyB,bool senderIsA)676*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
677*789431f2SAndroid Build Coastguard Worker                                         const bytevec& pubKeyB, bool senderIsA) {
678*789431f2SAndroid Build Coastguard Worker     if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) {
679*789431f2SAndroid Build Coastguard Worker         return "Missing input key parameters";
680*789431f2SAndroid Build Coastguard Worker     }
681*789431f2SAndroid Build Coastguard Worker 
682*789431f2SAndroid Build Coastguard Worker     bytevec rawSharedKey(X25519_SHARED_KEY_LEN);
683*789431f2SAndroid Build Coastguard Worker     if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) {
684*789431f2SAndroid Build Coastguard Worker         return "ECDH operation failed";
685*789431f2SAndroid Build Coastguard Worker     }
686*789431f2SAndroid Build Coastguard Worker 
687*789431f2SAndroid Build Coastguard Worker     auto kdfContext = consructKdfContext(pubKeyA, privKeyA, pubKeyB, senderIsA);
688*789431f2SAndroid Build Coastguard Worker     if (!kdfContext) return kdfContext.moveMessage();
689*789431f2SAndroid Build Coastguard Worker 
690*789431f2SAndroid Build Coastguard Worker     bytevec retval(SHA256_DIGEST_LENGTH);
691*789431f2SAndroid Build Coastguard Worker     bytevec salt{};
692*789431f2SAndroid Build Coastguard Worker     if (!HKDF(retval.data(), retval.size(),              //
693*789431f2SAndroid Build Coastguard Worker               EVP_sha256(),                              //
694*789431f2SAndroid Build Coastguard Worker               rawSharedKey.data(), rawSharedKey.size(),  //
695*789431f2SAndroid Build Coastguard Worker               salt.data(), salt.size(),                  //
696*789431f2SAndroid Build Coastguard Worker               kdfContext->data(), kdfContext->size())) {
697*789431f2SAndroid Build Coastguard Worker         return "ECDH HKDF failed";
698*789431f2SAndroid Build Coastguard Worker     }
699*789431f2SAndroid Build Coastguard Worker 
700*789431f2SAndroid Build Coastguard Worker     return retval;
701*789431f2SAndroid Build Coastguard Worker }
702*789431f2SAndroid Build Coastguard Worker 
aesGcmEncrypt(const bytevec & key,const bytevec & nonce,const bytevec & aad,const bytevec & plaintext)703*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
704*789431f2SAndroid Build Coastguard Worker                                 const bytevec& plaintext) {
705*789431f2SAndroid Build Coastguard Worker     auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */);
706*789431f2SAndroid Build Coastguard Worker     if (!ctx) return ctx.moveMessage();
707*789431f2SAndroid Build Coastguard Worker 
708*789431f2SAndroid Build Coastguard Worker     bytevec ciphertext(plaintext.size() + kAesGcmTagSize);
709*789431f2SAndroid Build Coastguard Worker     int outlen;
710*789431f2SAndroid Build Coastguard Worker     if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(),
711*789431f2SAndroid Build Coastguard Worker                           plaintext.size())) {
712*789431f2SAndroid Build Coastguard Worker         return "Failed to encrypt plaintext";
713*789431f2SAndroid Build Coastguard Worker     }
714*789431f2SAndroid Build Coastguard Worker     assert(plaintext.size() == static_cast<uint64_t>(outlen));
715*789431f2SAndroid Build Coastguard Worker 
716*789431f2SAndroid Build Coastguard Worker     if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) {
717*789431f2SAndroid Build Coastguard Worker         return "Failed to finalize encryption";
718*789431f2SAndroid Build Coastguard Worker     }
719*789431f2SAndroid Build Coastguard Worker     assert(outlen == 0);
720*789431f2SAndroid Build Coastguard Worker 
721*789431f2SAndroid Build Coastguard Worker     if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
722*789431f2SAndroid Build Coastguard Worker                              ciphertext.data() + plaintext.size())) {
723*789431f2SAndroid Build Coastguard Worker         return "Failed to retrieve tag";
724*789431f2SAndroid Build Coastguard Worker     }
725*789431f2SAndroid Build Coastguard Worker 
726*789431f2SAndroid Build Coastguard Worker     return ciphertext;
727*789431f2SAndroid Build Coastguard Worker }
728*789431f2SAndroid Build Coastguard Worker 
aesGcmDecrypt(const bytevec & key,const bytevec & nonce,const bytevec & aad,const bytevec & ciphertextWithTag)729*789431f2SAndroid Build Coastguard Worker ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
730*789431f2SAndroid Build Coastguard Worker                                 const bytevec& ciphertextWithTag) {
731*789431f2SAndroid Build Coastguard Worker     auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */);
732*789431f2SAndroid Build Coastguard Worker     if (!ctx) return ctx.moveMessage();
733*789431f2SAndroid Build Coastguard Worker 
734*789431f2SAndroid Build Coastguard Worker     if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag";
735*789431f2SAndroid Build Coastguard Worker 
736*789431f2SAndroid Build Coastguard Worker     bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize);
737*789431f2SAndroid Build Coastguard Worker     int outlen;
738*789431f2SAndroid Build Coastguard Worker     if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(),
739*789431f2SAndroid Build Coastguard Worker                           ciphertextWithTag.size() - kAesGcmTagSize)) {
740*789431f2SAndroid Build Coastguard Worker         return "Failed to decrypt plaintext";
741*789431f2SAndroid Build Coastguard Worker     }
742*789431f2SAndroid Build Coastguard Worker     assert(plaintext.size() == static_cast<uint64_t>(outlen));
743*789431f2SAndroid Build Coastguard Worker 
744*789431f2SAndroid Build Coastguard Worker     bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end());
745*789431f2SAndroid Build Coastguard Worker     if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) {
746*789431f2SAndroid Build Coastguard Worker         return "Failed to set tag: " + std::to_string(ERR_peek_last_error());
747*789431f2SAndroid Build Coastguard Worker     }
748*789431f2SAndroid Build Coastguard Worker 
749*789431f2SAndroid Build Coastguard Worker     if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) {
750*789431f2SAndroid Build Coastguard Worker         return "Failed to finalize encryption";
751*789431f2SAndroid Build Coastguard Worker     }
752*789431f2SAndroid Build Coastguard Worker     assert(outlen == 0);
753*789431f2SAndroid Build Coastguard Worker 
754*789431f2SAndroid Build Coastguard Worker     return plaintext;
755*789431f2SAndroid Build Coastguard Worker }
756*789431f2SAndroid Build Coastguard Worker 
sha256(const bytevec & data)757*789431f2SAndroid Build Coastguard Worker bytevec sha256(const bytevec& data) {
758*789431f2SAndroid Build Coastguard Worker     bytevec ret(SHA256_DIGEST_LENGTH);
759*789431f2SAndroid Build Coastguard Worker     SHA256_CTX ctx;
760*789431f2SAndroid Build Coastguard Worker     SHA256_Init(&ctx);
761*789431f2SAndroid Build Coastguard Worker     SHA256_Update(&ctx, data.data(), data.size());
762*789431f2SAndroid Build Coastguard Worker     SHA256_Final((unsigned char*)ret.data(), &ctx);
763*789431f2SAndroid Build Coastguard Worker     return ret;
764*789431f2SAndroid Build Coastguard Worker }
765*789431f2SAndroid Build Coastguard Worker 
sha384(const bytevec & data)766*789431f2SAndroid Build Coastguard Worker bytevec sha384(const bytevec& data) {
767*789431f2SAndroid Build Coastguard Worker     bytevec ret(SHA384_DIGEST_LENGTH);
768*789431f2SAndroid Build Coastguard Worker     SHA512_CTX ctx;
769*789431f2SAndroid Build Coastguard Worker     SHA384_Init(&ctx);
770*789431f2SAndroid Build Coastguard Worker     SHA384_Update(&ctx, data.data(), data.size());
771*789431f2SAndroid Build Coastguard Worker     SHA384_Final((unsigned char*)ret.data(), &ctx);
772*789431f2SAndroid Build Coastguard Worker     return ret;
773*789431f2SAndroid Build Coastguard Worker }
774*789431f2SAndroid Build Coastguard Worker 
775*789431f2SAndroid Build Coastguard Worker }  // namespace cppcose
776