changed Wallet from RSA to ECSDA cryto

This commit is contained in:
unknown 2017-11-07 16:15:48 -08:00
parent c1dfa24c12
commit f997ad4628

View file

@ -32,6 +32,7 @@
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/ecdsa.h>
// I know, right? But per https://www.openssl.org/docs/faq.html
// this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink
@ -78,18 +79,19 @@ int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
}
}
RSA* readKeys(const char* filename) {
EC_KEY* readKeys(const char* filename) {
FILE* fp;
RSA* key = NULL;
EC_KEY *key = NULL;
if ((fp = fopen(filename, "rt"))) {
// file opened successfully
qCDebug(commerce) << "opened key file" << filename;
if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) {
if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) {
// now read private key
qCDebug(commerce) << "read public key";
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) {
qCDebug(commerce) << "read private key";
fclose(fp);
return key;
@ -137,18 +139,18 @@ bool Wallet::writeBackupInstructions() {
return retval;
}
bool writeKeys(const char* filename, RSA* keys) {
bool writeKeys(const char* filename, EC_KEY* keys) {
FILE* fp;
bool retval = false;
if ((fp = fopen(filename, "wt"))) {
if (!PEM_write_RSAPublicKey(fp, keys)) {
if (!PEM_write_EC_PUBKEY(fp, keys)) {
fclose(fp);
qCDebug(commerce) << "failed to write public key";
QFile(QString(filename)).remove();
return retval;
}
if (!PEM_write_RSAPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
if (!PEM_write_ECPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
fclose(fp);
qCDebug(commerce) << "failed to write private key";
QFile(QString(filename)).remove();
@ -170,44 +172,28 @@ bool writeKeys(const char* filename, RSA* keys) {
// TODO: we don't really use the private keys returned - we can see how this evolves, but probably
// we should just return a list of public keys?
// or perhaps return the RSA* instead?
QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
RSA* keyPair = RSA_new();
BIGNUM* exponent = BN_new();
QPair<QByteArray*, QByteArray*> generateECKeypair() {
EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1);
QPair<QByteArray*, QByteArray*> retval;
const unsigned long RSA_KEY_EXPONENT = 65537;
BN_set_word(exponent, RSA_KEY_EXPONENT);
// seed the random number generator before we call RSA_generate_key_ex
srand(time(NULL));
const int RSA_KEY_BITS = 2048;
if (!RSA_generate_key_ex(keyPair, RSA_KEY_BITS, exponent, NULL)) {
qCDebug(commerce) << "Error generating 2048-bit RSA Keypair -" << ERR_get_error();
// we're going to bust out of here but first we cleanup the BIGNUM
BN_free(exponent);
if (!EC_KEY_generate_key(keyPair)) {
qCDebug(commerce) << "Error generating EC Keypair -" << ERR_get_error();
return retval;
}
// we don't need the BIGNUM anymore so clean that up
BN_free(exponent);
// grab the public key and private key from the file
unsigned char* publicKeyDER = NULL;
int publicKeyLength = i2d_RSAPublicKey(keyPair, &publicKeyDER);
int publicKeyLength = i2d_EC_PUBKEY(keyPair, &publicKeyDER);
unsigned char* privateKeyDER = NULL;
int privateKeyLength = i2d_RSAPrivateKey(keyPair, &privateKeyDER);
int privateKeyLength = i2d_ECPrivateKey(keyPair, &privateKeyDER);
if (publicKeyLength <= 0 || privateKeyLength <= 0) {
qCDebug(commerce) << "Error getting DER public or private key from RSA struct -" << ERR_get_error();
// cleanup the RSA struct
RSA_free(keyPair);
EC_KEY_free(keyPair);
// cleanup the public and private key DER data, if required
if (publicKeyLength > 0) {
@ -227,7 +213,7 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
return retval;
}
RSA_free(keyPair);
EC_KEY_free(keyPair);
// prepare the return values. TODO: Fix this - we probably don't really even want the
// private key at all (better to read it when we need it?). Or maybe we do, when we have
@ -245,18 +231,18 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
// the public key can just go into a byte array
QByteArray readPublicKey(const char* filename) {
FILE* fp;
RSA* key = NULL;
EC_KEY* key = NULL;
if ((fp = fopen(filename, "r"))) {
// file opened successfully
qCDebug(commerce) << "opened key file" << filename;
if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) {
if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) {
// file read successfully
unsigned char* publicKeyDER = NULL;
int publicKeyLength = i2d_RSAPublicKey(key, &publicKeyDER);
int publicKeyLength = i2d_EC_PUBKEY(key, &publicKeyDER);
// TODO: check for 0 length?
// cleanup
RSA_free(key);
EC_KEY_free(key);
fclose(fp);
qCDebug(commerce) << "parsed public key file successfully";
@ -274,15 +260,15 @@ QByteArray readPublicKey(const char* filename) {
return QByteArray();
}
// the private key should be read/copied into heap memory. For now, we need the RSA struct
// the private key should be read/copied into heap memory. For now, we need the EC_KEY struct
// so I'll return that. Note we need to RSA_free(key) later!!!
RSA* readPrivateKey(const char* filename) {
EC_KEY* readPrivateKey(const char* filename) {
FILE* fp;
RSA* key = NULL;
EC_KEY* key = NULL;
if ((fp = fopen(filename, "r"))) {
// file opened successfully
qCDebug(commerce) << "opened key file" << filename;
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) {
qCDebug(commerce) << "parsed private key file successfully";
} else {
@ -509,7 +495,7 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
if (publicKey.size() > 0) {
if (auto key = readPrivateKey(keyFilePath().toStdString().c_str())) {
RSA_free(key);
EC_KEY_free(key);
// be sure to add the public key so we don't do this over and over
_publicKeys.push_back(publicKey.toBase64());
@ -525,7 +511,7 @@ bool Wallet::generateKeyPair() {
initialize();
qCInfo(commerce) << "Generating keypair.";
auto keyPair = generateRSAKeypair();
auto keyPair = generateECKeypair();
writeBackupInstructions();
@ -558,22 +544,30 @@ QStringList Wallet::listPublicKeys() {
// encoded string representing the signature (suitable for http, etc...)
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
qCInfo(commerce) << "Signing text.";
RSA* rsaPrivateKey = NULL;
if ((rsaPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
QByteArray signature(RSA_size(rsaPrivateKey), 0);
EC_KEY* ecPrivateKey = NULL;
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
QByteArray signature(ECDSA_size(ecPrivateKey), 0);
unsigned int signatureBytes = 0;
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
int encryptReturn = RSA_sign(NID_sha256,
reinterpret_cast<const unsigned char*>(hashedPlaintext.constData()),
hashedPlaintext.size(),
reinterpret_cast<unsigned char*>(signature.data()),
&signatureBytes,
rsaPrivateKey);
int encryptReturn = ECDSA_sign(0,
reinterpret_cast<const unsigned char*>(hashedPlaintext.constData()),
hashedPlaintext.size(),
reinterpret_cast<unsigned char*>(signature.data()),
&signatureBytes, ecPrivateKey);
//Previous pattern, retained by ECDSA_sign
//int encryptReturn = RSA_sign(NID_sha256,
// reinterpret_cast<const unsigned char*>(hashedPlaintext.constData()),
// hashedPlaintext.size(),
// reinterpret_cast<unsigned char*>(signature.data()),
// &signatureBytes,
// rsaPrivateKey);
// free the private key RSA struct now that we are done with it
RSA_free(rsaPrivateKey);
EC_KEY_free(ecPrivateKey);
if (encryptReturn != -1) {
return signature.toBase64();
@ -674,7 +668,7 @@ void Wallet::reset() {
keyFile.remove();
}
bool Wallet::writeWallet(const QString& newPassphrase) {
RSA* keys = readKeys(keyFilePath().toStdString().c_str());
EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str());
if (keys) {
// we read successfully, so now write to a new temp file
QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp"));
@ -720,18 +714,23 @@ bool Wallet::changePassphrase(const QString& newPassphrase) {
void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
auto nodeList = DependencyManager::get<NodeList>();
//With EC keys, we receive a nonce from the metaverse server, which is signed
//here with the private key and returned. Verification is done at server.
bool challengeOriginatedFromClient = packet->getType() == PacketType::ChallengeOwnershipRequest;
unsigned char decryptedText[64];
//unsigned char decryptedText[64];
int decryptionStatus;
int certIDByteArraySize;
int encryptedTextByteArraySize;
int challengingNodeUUIDByteArraySize;
packet->readPrimitive(&certIDByteArraySize);
packet->readPrimitive(&encryptedTextByteArraySize);
packet->readPrimitive(&encryptedTextByteArraySize); //rerturns a cast char*, size
if (challengeOriginatedFromClient) {
packet->readPrimitive(&challengingNodeUUIDByteArraySize);
}
//"encryptedText" is now a series of random bytes, a nonce
QByteArray certID = packet->read(certIDByteArraySize);
QByteArray encryptedText = packet->read(encryptedTextByteArraySize);
QByteArray challengingNodeUUID;
@ -739,25 +738,34 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
challengingNodeUUID = packet->read(challengingNodeUUIDByteArraySize);
}
RSA* rsa = readKeys(keyFilePath().toStdString().c_str());
int decryptionStatus = -1;
EC_KEY* ec = readKeys(keyFilePath().toStdString().c_str());
QString sig;
// int decryptionStatus = -1;
if (rsa) {
if (ec) {
ERR_clear_error();
decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize,
reinterpret_cast<const unsigned char*>(encryptedText.constData()),
decryptedText,
rsa,
RSA_PKCS1_OAEP_PADDING);
sig = signWithKey(encryptedText, ""); //base64 signature, QByteArray cast
//upon return to QString
RSA_free(rsa);
// decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize,
// reinterpret_cast<const unsigned char*>(encryptedText.constData()),
// decryptedText, //unsigned char*
// ec,
// RSA_PKCS1_OAEP_PADDING);
EC_KEY_free(ec);
decryptionStatus = 1;
} else {
qCDebug(commerce) << "During entity ownership challenge, creating the RSA object failed.";
qCDebug(commerce) << "During entity ownership challenge, creating the EC-signed nonce failed.";
decryptionStatus = -1;
}
QByteArray ba = sig.toLocal8Bit();
const char *sigChar = ba.data();
QByteArray decryptedTextByteArray;
if (decryptionStatus > -1) {
decryptedTextByteArray = QByteArray(reinterpret_cast<const char*>(decryptedText), decryptionStatus);
decryptedTextByteArray = QByteArray(sigChar, decryptionStatus);
}
int decryptedTextByteArraySize = decryptedTextByteArray.size();
int certIDSize = certID.size();
@ -774,7 +782,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
decryptedTextPacket->write(decryptedTextByteArray);
decryptedTextPacket->write(challengingNodeUUID);
qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID;
qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing signed text" << decryptedTextByteArray << "for CertID" << certID;
nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode);
} else {
@ -785,17 +793,17 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
decryptedTextPacket->write(certID);
decryptedTextPacket->write(decryptedTextByteArray);
qCDebug(commerce) << "Sending ChallengeOwnership Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID;
qCDebug(commerce) << "Sending ChallengeOwnership Packet containing signed text" << decryptedTextByteArray << "for CertID" << certID;
nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode);
}
if (decryptionStatus == -1) {
qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed.";
qCDebug(commerce) << "During entity ownership challenge, signing the text failed.";
long error = ERR_get_error();
if (error != 0) {
const char* error_str = ERR_error_string(error, NULL);
qCWarning(entities) << "RSA error:" << error_str;
qCWarning(entities) << "EC error:" << error_str;
}
}
}
@ -818,4 +826,4 @@ void Wallet::getWalletStatus() {
walletScriptingInterface->setWalletStatus(status);
return;
}
}
}