// Copyright 2014 Google LLC. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd // // RSA signature details: // Algorithm: RSASSA-PSS // Hash algorithm: SHA1 // Mask generation function: mgf1SHA1 // Salt length: 20 bytes // Trailer field: 0xbc // // RSA encryption details: // Algorithm: RSA-OAEP // Mask generation function: mgf1SHA1 // Label (encoding paramter): empty std::string #include "packager/media/base/rsa_key.h" #include #include #include #include #include namespace { const size_t kPssSaltLength = 20u; std::string mbedtls_strerr(int rv) { // There is always a "high level" error. std::string output(mbedtls_high_level_strerr(rv)); // Some errors have a "low level" error, which is like an inner error code // with a deeper explanation. But on mac and Windows, ostream crashes if you // give it NULL. So we combine them ourselves with a NULL check. const char* low_level_error = mbedtls_low_level_strerr(rv); if (low_level_error) { output += ": "; output += low_level_error; } return output; } std::string sha1(const std::string& message) { const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); DCHECK(md_info); std::string hash(mbedtls_md_get_size(md_info), 0); CHECK_EQ(0, mbedtls_md(md_info, reinterpret_cast(message.data()), message.size(), reinterpret_cast(hash.data()))); return hash; } } // namespace namespace shaka { namespace media { RsaPrivateKey::RsaPrivateKey() { mbedtls_pk_init(&pk_context_); mbedtls_entropy_init(&entropy_context_); mbedtls_ctr_drbg_init(&prng_context_); } RsaPrivateKey::~RsaPrivateKey() { mbedtls_pk_free(&pk_context_); mbedtls_entropy_free(&entropy_context_); mbedtls_ctr_drbg_free(&prng_context_); } RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_key) { std::unique_ptr key(new RsaPrivateKey()); if (!key->Deserialize(serialized_key)) { return NULL; } return key.release(); } bool RsaPrivateKey::Deserialize(const std::string& serialized_key) { const mbedtls_pk_info_t* pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); DCHECK(pk_info); CHECK_EQ(mbedtls_ctr_drbg_seed(&prng_context_, mbedtls_entropy_func, &entropy_context_, /* custom= */ NULL, /* custom_len= */ 0), 0); int rv = mbedtls_pk_parse_key( &pk_context_, reinterpret_cast(serialized_key.data()), serialized_key.size(), /* password= */ NULL, /* password_len= */ 0, mbedtls_ctr_drbg_random, &prng_context_); if (rv != 0) { LOG(ERROR) << "RSA private key failed to load: " << mbedtls_strerr(rv); return false; } // Set the padding mode and digest mode. mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_); rv = mbedtls_rsa_set_padding(rsa_context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); if (rv != 0) { LOG(ERROR) << "RSA private key failed to set padding: " << mbedtls_strerr(rv); return false; } return true; } bool RsaPrivateKey::Decrypt(const std::string& encrypted_message, std::string* decrypted_message) { DCHECK(decrypted_message); mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_); size_t rsa_size = mbedtls_rsa_get_len(rsa_context); if (encrypted_message.size() != rsa_size) { LOG(ERROR) << "Encrypted RSA message has the wrong size (expected " << rsa_size << ", actual " << encrypted_message.size() << ")."; return false; } decrypted_message->resize(encrypted_message.size()); size_t decrypted_size = 0; int rv = mbedtls_rsa_rsaes_oaep_decrypt( rsa_context, mbedtls_ctr_drbg_random, &prng_context_, /* label= */ NULL, /* label_len= */ 0, &decrypted_size, reinterpret_cast(encrypted_message.data()), reinterpret_cast(decrypted_message->data()), decrypted_message->size()); if (rv != 0) { LOG(ERROR) << "RSA private decrypt failure: " << mbedtls_strerr(rv); return false; } decrypted_message->resize(decrypted_size); return true; } bool RsaPrivateKey::GenerateSignature(const std::string& message, std::string* signature) { DCHECK(signature); if (message.empty()) { LOG(ERROR) << "Message to be signed is empty."; return false; } mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_); size_t rsa_size = mbedtls_rsa_get_len(rsa_context); signature->resize(rsa_size); std::string hash = sha1(message); int rv = mbedtls_rsa_rsassa_pss_sign_ext( rsa_context, mbedtls_ctr_drbg_random, &prng_context_, MBEDTLS_MD_SHA1, static_cast(hash.size()), reinterpret_cast(hash.data()), kPssSaltLength, reinterpret_cast(signature->data())); if (rv != 0) { LOG(ERROR) << "RSA sign failure: " << mbedtls_strerr(rv); return false; } return true; } RsaPublicKey::RsaPublicKey() { mbedtls_pk_init(&pk_context_); mbedtls_entropy_init(&entropy_context_); mbedtls_ctr_drbg_init(&prng_context_); } RsaPublicKey::~RsaPublicKey() { mbedtls_pk_free(&pk_context_); mbedtls_entropy_free(&entropy_context_); mbedtls_ctr_drbg_free(&prng_context_); } RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_key) { std::unique_ptr key(new RsaPublicKey()); if (!key->Deserialize(serialized_key)) { return NULL; } return key.release(); } bool RsaPublicKey::Deserialize(const std::string& serialized_key) { const mbedtls_pk_info_t* pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); DCHECK(pk_info); CHECK_EQ(mbedtls_ctr_drbg_seed(&prng_context_, mbedtls_entropy_func, &entropy_context_, /* custom= */ NULL, /* custom_len= */ 0), 0); int rv = mbedtls_pk_parse_public_key( &pk_context_, reinterpret_cast(serialized_key.data()), serialized_key.size()); if (rv != 0) { LOG(ERROR) << "RSA public key failed to load: " << mbedtls_strerr(rv); return false; } // Set the padding mode and digest mode. mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_); rv = mbedtls_rsa_set_padding(rsa_context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); if (rv != 0) { LOG(ERROR) << "RSA public key failed to set padding: " << mbedtls_strerr(rv); return false; } return true; } bool RsaPublicKey::Encrypt(const std::string& clear_message, std::string* encrypted_message) { DCHECK(encrypted_message); if (clear_message.empty()) { LOG(ERROR) << "Message to be encrypted is empty."; return false; } mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_); size_t rsa_size = mbedtls_rsa_get_len(rsa_context); encrypted_message->resize(rsa_size); int rv = mbedtls_rsa_rsaes_oaep_encrypt( rsa_context, mbedtls_ctr_drbg_random, &prng_context_, /* label= */ NULL, /* label_len= */ 0, clear_message.size(), reinterpret_cast(clear_message.data()), reinterpret_cast(encrypted_message->data())); if (rv != 0) { LOG(ERROR) << "RSA public encrypt failure: " << mbedtls_strerr(rv); return false; } return true; } bool RsaPublicKey::VerifySignature(const std::string& message, const std::string& signature) { if (message.empty()) { LOG(ERROR) << "Signed message is empty."; return false; } mbedtls_rsa_context* rsa_context = mbedtls_pk_rsa(pk_context_); size_t rsa_size = mbedtls_rsa_get_len(rsa_context); if (signature.size() != rsa_size) { LOG(ERROR) << "Message signature is of the wrong size (expected " << rsa_size << ", actual " << signature.size() << ")."; return false; } // Verify the signature. std::string hash = sha1(message); int rv = mbedtls_rsa_rsassa_pss_verify_ext( rsa_context, MBEDTLS_MD_SHA1, static_cast(hash.size()), reinterpret_cast(hash.data()), MBEDTLS_MD_SHA1, kPssSaltLength, reinterpret_cast(signature.data())); if (rv != 0) { LOG(ERROR) << "RSA signature verification failed: " << mbedtls_strerr(rv); return false; } return true; } } // namespace media } // namespace shaka