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