Implement RsaPrivateKey and RsaPublicKey.
Used for message signing, signature verification, encryption and decryption using RSA algorithm. Change-Id: Icacd5a994c532a7bd4179c44e98c3ee9db744e83
This commit is contained in:
parent
1e7080dda6
commit
ffc4a82460
|
@ -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
|
|
@ -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_
|
Loading…
Reference in New Issue