Implement RsaPrivateKey and RsaPublicKey.

Used for message signing, signature verification, encryption and
decryption using RSA algorithm.

Change-Id: Icacd5a994c532a7bd4179c44e98c3ee9db744e83
This commit is contained in:
Kongqun Yang 2014-01-06 15:38:39 -08:00 committed by KongQun Yang
parent 1e7080dda6
commit ffc4a82460
2 changed files with 321 additions and 0 deletions

246
media/base/rsa_key.cc Normal file
View File

@ -0,0 +1,246 @@
// Copyright (c) 2013 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// 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 "media/base/rsa_key.h"
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <vector>
#include "base/logging.h"
#include "base/sha1.h"
#include "base/stl_util.h"
namespace {
const size_t kPssSaltLength = 20u;
// Serialize rsa key from DER encoded PKCS#1 RSAPrivateKey.
RSA* DeserializeRsaKey(const std::string& serialized_key,
bool deserialize_private_key) {
if (serialized_key.empty()) {
LOG(ERROR) << "Serialized RSA Key is empty.";
return NULL;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_key.data()),
serialized_key.size());
if (bio == NULL) {
LOG(ERROR) << "BIO_new_mem_buf returned NULL.";
return NULL;
}
RSA* rsa_key = deserialize_private_key ? d2i_RSAPrivateKey_bio(bio, NULL)
: d2i_RSAPublicKey_bio(bio, NULL);
BIO_free(bio);
return rsa_key;
}
RSA* DeserializeRsaPrivateKey(const std::string& serialized_key) {
RSA* rsa_key = DeserializeRsaKey(serialized_key, true);
if (!rsa_key) {
LOG(ERROR) << "Private RSA key deserialization failure.";
return NULL;
}
if (RSA_check_key(rsa_key) != 1) {
LOG(ERROR) << "Invalid RSA Private key: " << ERR_error_string(
ERR_get_error(), NULL);
RSA_free(rsa_key);
return NULL;
}
return rsa_key;
}
RSA* DeserializeRsaPublicKey(const std::string& serialized_key) {
RSA* rsa_key = DeserializeRsaKey(serialized_key, false);
if (!rsa_key) {
LOG(ERROR) << "Private RSA key deserialization failure.";
return NULL;
}
if (RSA_size(rsa_key) <= 0) {
LOG(ERROR) << "Invalid RSA Public key: " << ERR_error_string(
ERR_get_error(), NULL);
RSA_free(rsa_key);
return NULL;
}
return rsa_key;
}
} // namespace
namespace media {
RsaPrivateKey::RsaPrivateKey(RSA* rsa_key) : rsa_key_(rsa_key) {
DCHECK(rsa_key);
}
RsaPrivateKey::~RsaPrivateKey() {
if (rsa_key_ != NULL)
RSA_free(rsa_key_);
}
RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_key) {
RSA* rsa_key = DeserializeRsaPrivateKey(serialized_key);
return rsa_key == NULL ? NULL : new RsaPrivateKey(rsa_key);
}
bool RsaPrivateKey::Decrypt(const std::string& encrypted_message,
std::string* decrypted_message) {
DCHECK(decrypted_message);
size_t rsa_size = RSA_size(rsa_key_);
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(rsa_size);
int decrypted_size = RSA_private_decrypt(
rsa_size,
reinterpret_cast<const uint8*>(encrypted_message.data()),
reinterpret_cast<uint8*>(string_as_array(decrypted_message)),
rsa_key_,
RSA_PKCS1_OAEP_PADDING);
if (decrypted_size == -1) {
LOG(ERROR) << "RSA private decrypt failure: " << ERR_error_string(
ERR_get_error(), NULL);
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;
}
std::string message_digest = base::SHA1HashString(message);
// Add PSS padding.
size_t rsa_size = RSA_size(rsa_key_);
std::vector<uint8> padded_digest(rsa_size);
if (!RSA_padding_add_PKCS1_PSS(
rsa_key_,
&padded_digest[0],
reinterpret_cast<uint8*>(string_as_array(&message_digest)),
EVP_sha1(),
kPssSaltLength)) {
LOG(ERROR) << "RSA padding failure: " << ERR_error_string(ERR_get_error(),
NULL);
return false;
}
// Encrypt PSS padded digest.
signature->resize(rsa_size);
int signature_size =
RSA_private_encrypt(padded_digest.size(),
&padded_digest[0],
reinterpret_cast<uint8*>(string_as_array(signature)),
rsa_key_,
RSA_NO_PADDING);
if (signature_size != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA private encrypt failure: " << ERR_error_string(
ERR_get_error(), NULL);
return false;
}
return true;
}
RsaPublicKey::RsaPublicKey(RSA* rsa_key) : rsa_key_(rsa_key) {
DCHECK(rsa_key);
}
RsaPublicKey::~RsaPublicKey() {
if (rsa_key_ != NULL)
RSA_free(rsa_key_);
}
RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_key) {
RSA* rsa_key = DeserializeRsaPublicKey(serialized_key);
return rsa_key == NULL ? NULL : new RsaPublicKey(rsa_key);
}
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;
}
size_t rsa_size = RSA_size(rsa_key_);
encrypted_message->resize(rsa_size);
int encrypted_size = RSA_public_encrypt(
clear_message.size(),
reinterpret_cast<const uint8*>(clear_message.data()),
reinterpret_cast<uint8*>(string_as_array(encrypted_message)),
rsa_key_,
RSA_PKCS1_OAEP_PADDING);
if (encrypted_size != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public encrypt failure: " << ERR_error_string(
ERR_get_error(), NULL);
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;
}
size_t rsa_size = RSA_size(rsa_key_);
if (signature.size() != rsa_size) {
LOG(ERROR) << "Message signature is of the wrong size (expected "
<< rsa_size << ", actual " << signature.size() << ").";
return false;
}
// Decrypt the signature.
std::vector<uint8> padded_digest(signature.size());
int decrypted_size =
RSA_public_decrypt(signature.size(),
reinterpret_cast<const uint8*>(signature.data()),
&padded_digest[0],
rsa_key_,
RSA_NO_PADDING);
if (decrypted_size != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public decrypt failure: " << ERR_error_string(
ERR_get_error(), NULL);
return false;
}
std::string message_digest = base::SHA1HashString(message);
// Verify PSS padding.
return RSA_verify_PKCS1_PSS(
rsa_key_,
reinterpret_cast<const uint8*>(message_digest.data()),
EVP_sha1(),
&padded_digest[0],
kPssSaltLength) != 0;
}
} // namespace media

75
media/base/rsa_key.h Normal file
View File

@ -0,0 +1,75 @@
// Copyright (c) 2013 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Declaration of classes representing RSA private and public keys used
// for message signing, signature verification, encryption and decryption.
#ifndef MEDIA_BASE_RSA_KEY_H_
#define MEDIA_BASE_RSA_KEY_H_
#include <string>
#include "base/basictypes.h"
struct rsa_st;
typedef struct rsa_st RSA;
namespace media {
class RsaPrivateKey {
public:
~RsaPrivateKey();
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
// Return NULL on failure.
static RsaPrivateKey* Create(const std::string& serialized_key);
// Decrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Return true if successful, false otherwise.
bool Decrypt(const std::string& encrypted_message,
std::string* decrypted_message);
// Generate RSASSA-PSS signature. Caller retains ownership of all parameters.
// Return true if successful, false otherwise.
bool GenerateSignature(const std::string& message, std::string* signature);
private:
// RsaPrivateKey takes owership of |rsa_key|.
explicit RsaPrivateKey(RSA* rsa_key);
RSA* rsa_key_; // owned
DISALLOW_COPY_AND_ASSIGN(RsaPrivateKey);
};
class RsaPublicKey {
public:
~RsaPublicKey();
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
// Return NULL on failure.
static RsaPublicKey* Create(const std::string& serialized_key);
// Encrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Return true if successful, false otherwise.
bool Encrypt(const std::string& clear_message,
std::string* encrypted_message);
// Verify RSASSA-PSS signature. Caller retains ownership of all parameters.
// Return true if validation succeeds, false otherwise.
bool VerifySignature(const std::string& message,
const std::string& signature);
private:
// RsaPublicKey takes owership of |rsa_key|.
explicit RsaPublicKey(RSA* rsa_key);
RSA* rsa_key_; // owned
DISALLOW_COPY_AND_ASSIGN(RsaPublicKey);
};
} // namespace media
#endif // MEDIA_BASE_RSA_KEY_H_