#include "KeyPairEd25519.h" #include #include "../SingletonManager/ErrorManager.h" #include "../lib/DataTypeConverter.h" KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey) : mSodiumSecret(privateKey) { //memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES); // read pubkey from private key, so we are sure it is the correct pubkey for the private key crypto_sign_ed25519_sk_to_pk(mSodiumPublic, *privateKey); } KeyPairEd25519::KeyPairEd25519(const unsigned char* publicKey) : mSodiumSecret(nullptr) { memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES); } KeyPairEd25519::KeyPairEd25519() : mSodiumSecret(nullptr) { memset(mSodiumPublic, 0, crypto_sign_PUBLICKEYBYTES); } KeyPairEd25519::~KeyPairEd25519() { if (mSodiumSecret) { MemoryManager::getInstance()->releaseMemory(mSodiumSecret); mSodiumSecret = nullptr; } } KeyPairEd25519* KeyPairEd25519::create(const Poco::AutoPtr passphrase) { //auto er = ErrorManager::getInstance(); auto mm = MemoryManager::getInstance(); assert(!passphrase.isNull()); // libsodium doc: https://libsodium.gitbook.io/doc/advanced/hmac-sha2 // https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki auto word_indices = passphrase->getWordIndices(); if (!word_indices || (!word_indices[0] && !word_indices[1] && !word_indices[2] && !word_indices[3])) { return nullptr; } std::string clear_passphrase = passphrase->createClearPassphrase(); unsigned char hash[crypto_hash_sha512_BYTES]; crypto_hash_sha512_state state; crypto_hash_sha512_init(&state); // **** convert word indices into uint64 **** // To prevent breaking existing passphrase-hash combinations word indices will be put into 64 Bit Variable to mimic first implementation of algorithms auto valueSize = sizeof(Poco::UInt64); Poco::UInt64 value = 0; for (int i = 0; i < PHRASE_WORD_COUNT; i++) { value = word_indices[i]; crypto_hash_sha512_update(&state, (const unsigned char*)&value, valueSize); } // **** end converting into uint64 ***** crypto_hash_sha512_update(&state, (unsigned char*)clear_passphrase.data(), clear_passphrase.size()); crypto_hash_sha512_final(&state, hash); /* // debug passphrase printf("\passsphrase: <%s>\n", passphrase); printf("size word indices: %u\n", word_indices->size()); std::string word_indicesHex = getHex(*word_indices, word_indices->size()); printf("word_indices: \n%s\n", word_indicesHex.data()); printf("word_indices: \n"); Poco::UInt64* word_indices_p = (Poco::UInt64*)(word_indices->data()); for (int i = 0; i < PHRASE_WORD_COUNT; i++) { if (i > 0) printf(" "); printf("%4hu", word_indices_p[i]); } printf("\n"); printf("\nclear passphrase: \n%s\n", clearPassphrase.data()); std::string hex_clearPassphrase = getHex((const unsigned char*)clearPassphrase.data(), clearPassphrase.size()); printf("passphrase bin: \n%s\n\n", hex_clearPassphrase.data()); //*/ KeyPairEd25519* key_pair = new KeyPairEd25519; if (!key_pair->mSodiumSecret) { key_pair->mSodiumSecret = mm->getFreeMemory(crypto_sign_SECRETKEYBYTES); } crypto_sign_seed_keypair(key_pair->mSodiumPublic, *key_pair->mSodiumSecret, hash); return key_pair; // print hex for all keys for debugging /* printf("// ********** Keys ************* //\n"); printf("Sodium Public: \t%s\n", getHex(mSodiumPublic, crypto_sign_PUBLICKEYBYTES).data()); printf("Sodium Private: \t%s\n", getHex(*mSodiumSecret, mSodiumSecret->size()).data()); printf("// ********* Keys End ************ //\n"); */ //printf("[KeyPair::generateFromPassphrase] finished!\n"); // using } MemoryBin* KeyPairEd25519::sign(const unsigned char* message, size_t messageSize) const //MemoryBin* KeyPairEd25519::sign(const MemoryBin* message) const { if (!message || !messageSize) return nullptr; if (!mSodiumSecret) return nullptr; auto mm = MemoryManager::getInstance(); auto em = ErrorManager::getInstance(); const static char functionName[] = "KeyPairEd25519::sign"; auto signBinBuffer = mm->getFreeMemory(crypto_sign_BYTES); unsigned long long actualSignLength = 0; if (crypto_sign_detached(*signBinBuffer, &actualSignLength, message, messageSize, *mSodiumSecret)) { em->addError(new Error(functionName, "sign failed")); auto messageHex = DataTypeConverter::binToHex(message, messageSize); em->addError(new ParamError(functionName, "message as hex", messageHex)); mm->releaseMemory(signBinBuffer); return nullptr; } if (crypto_sign_verify_detached(*signBinBuffer, message, messageSize, mSodiumPublic) != 0) { // Incorrect signature! //printf("c[KeyBuffer::%s] sign verify failed\n", __FUNCTION__); em->addError(new Error(functionName, "sign verify failed")); auto messageHex = DataTypeConverter::binToHex(message, messageSize); em->addError(new ParamError(functionName, "message as hex", messageHex)); mm->releaseMemory(signBinBuffer); return nullptr; } // debug /*const size_t hex_sig_size = crypto_sign_BYTES * 2 + 1; char sig_hex[hex_sig_size]; sodium_bin2hex(sig_hex, hex_sig_size, *signBinBuffer, crypto_sign_BYTES); printf("[User::sign] signature hex: %s\n", sig_hex); */ return signBinBuffer; } bool KeyPairEd25519::verify(const std::string& message, const std::string& signature) const { if (message == "" || signature == "") return false; if (crypto_sign_verify_detached((const unsigned char*)signature.data(), (const unsigned char*)message.data(), message.size(), mSodiumPublic) != 0) { return false; } return true; } MemoryBin* KeyPairEd25519::getCryptedPrivKey(const Poco::AutoPtr password) const { if (password.isNull()) return nullptr; if (!mSodiumSecret) return nullptr; MemoryBin* encryptedKey = nullptr; if (SecretKeyCryptography::AUTH_ENCRYPT_OK == password->encrypt(mSodiumSecret, &encryptedKey)) { return encryptedKey; } else { return nullptr; } }