15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file. 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <cryptohi.h> 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/numerics/safe_math.h" 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/stl_util.h" 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/child/webcrypto/crypto_data.h" 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/child/webcrypto/nss/aes_key_nss.h" 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/child/webcrypto/nss/key_nss.h" 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/child/webcrypto/nss/util_nss.h" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/child/webcrypto/status.h" 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/child/webcrypto/webcrypto_util.h" 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "crypto/scoped_nss_types.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace content { 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace webcrypto { 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace { 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const blink::WebCryptoAlgorithm& algorithm, 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const blink::WebCryptoKey& key, 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const CryptoData& data, 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<uint8_t>* buffer) { 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!params) 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::ErrorUnexpected(); 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CryptoData iv(params->iv().data(), params->iv().size()); 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (iv.byte_length() != 16) 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::ErrorIncorrectSizeAesCbcIv(); 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PK11SymKey* sym_key = SymKeyNss::Cast(key)->key(); 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT; 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SECItem iv_item = MakeSECItemForBuffer(iv); 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!param) 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::OperationError(); 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CKM_AES_CBC_PAD, operation, sym_key, param.get())); 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!context.get()) 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::OperationError(); 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Oddly PK11_CipherOp takes input and output lengths as "int" rather than 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // "unsigned int". Do some checks now to avoid integer overflowing. 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::CheckedNumeric<int> output_max_len = data.byte_length(); 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) output_max_len += AES_BLOCK_SIZE; 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!output_max_len.IsValid()) { 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // TODO(eroman): Handle this by chunking the input fed into NSS. Right now 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // it doesn't make much difference since the one-shot API would end up 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // blowing out the memory and crashing anyway. 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::ErrorDataTooLarge(); 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // PK11_CipherOp does an invalid memory access when given empty decryption 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // input, or input which is not a multiple of the block size. See also 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (operation == CKA_DECRYPT && 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) { 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::OperationError(); 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // TODO(eroman): Refine the output buffer size. It can be computed exactly for 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // encryption, and can be smaller for decryption. 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer->resize(output_max_len.ValueOrDie()); 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) unsigned char* buffer_data = vector_as_array(buffer); 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int output_len; 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (SECSuccess != PK11_CipherOp(context.get(), 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_data, 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &output_len, 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer->size(), 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data.bytes(), 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data.byte_length())) { 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::OperationError(); 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) unsigned int final_output_chunk_len; 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (SECSuccess != 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PK11_DigestFinal(context.get(), 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer_data + output_len, 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &final_output_chunk_len, 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (output_max_len - output_len).ValueOrDie())) { 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::OperationError(); 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) buffer->resize(final_output_chunk_len + output_len); 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status::Success(); 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class AesCbcImplementation : public AesAlgorithm { 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public: 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) AesCbcImplementation() : AesAlgorithm(CKM_AES_CBC, "CBC") {} 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const blink::WebCryptoKey& key, 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const CryptoData& data, 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<uint8_t>* buffer) const OVERRIDE { 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return AesCbcEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer); 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const blink::WebCryptoKey& key, 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const CryptoData& data, 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<uint8_t>* buffer) const OVERRIDE { 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return AesCbcEncryptDecrypt(DECRYPT, algorithm, key, data, buffer); 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)AlgorithmImplementation* CreatePlatformAesCbcImplementation() { 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return new AesCbcImplementation; 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace webcrypto 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace content 129