diff options
Diffstat (limited to 'security/nss/nss-tool/enc/enctool.cc')
-rw-r--r-- | security/nss/nss-tool/enc/enctool.cc | 464 |
1 files changed, 0 insertions, 464 deletions
diff --git a/security/nss/nss-tool/enc/enctool.cc b/security/nss/nss-tool/enc/enctool.cc deleted file mode 100644 index b3c0d1dbe..000000000 --- a/security/nss/nss-tool/enc/enctool.cc +++ /dev/null @@ -1,464 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "enctool.h" -#include "argparse.h" -#include "util.h" - -#include "nss.h" - -#include <assert.h> -#include <chrono> -#include <fstream> -#include <iomanip> -#include <iostream> - -void EncTool::PrintError(const std::string& m, size_t line_number) { - std::cerr << m << " - enctool.cc:" << line_number << std::endl; -} - -void EncTool::PrintError(const std::string& m, PRErrorCode err, - size_t line_number) { - std::cerr << m << " (error " << err << ")" - << " - enctool.cc:" << line_number << std::endl; -} - -void EncTool::PrintBytes(const std::vector<uint8_t>& bytes, - const std::string& txt) { - if (debug_) { - std::cerr << txt << ": "; - for (uint8_t b : bytes) { - std::cerr << std::setfill('0') << std::setw(2) << std::hex - << static_cast<int>(b); - } - std::cerr << std::endl << std::dec; - } -} - -std::vector<uint8_t> EncTool::GenerateRandomness(size_t num_bytes) { - std::vector<uint8_t> bytes(num_bytes); - if (PK11_GenerateRandom(bytes.data(), num_bytes) != SECSuccess) { - PrintError("No randomness available. Abort!", __LINE__); - exit(1); - } - return bytes; -} - -bool EncTool::WriteBytes(const std::vector<uint8_t>& bytes, - std::string out_file) { - std::fstream output(out_file, std::ios::out | std::ios::binary); - if (!output.good()) { - return false; - } - output.write(reinterpret_cast<const char*>( - const_cast<const unsigned char*>(bytes.data())), - bytes.size()); - output.flush(); - output.close(); - return true; -} - -bool EncTool::GetKey(const std::vector<uint8_t>& key_bytes, - ScopedSECItem& key_item) { - if (key_bytes.empty()) { - return false; - } - - // Build key. - key_item = - ScopedSECItem(SECITEM_AllocItem(nullptr, nullptr, key_bytes.size())); - if (!key_item) { - return false; - } - key_item->type = siBuffer; - memcpy(key_item->data, key_bytes.data(), key_bytes.size()); - key_item->len = key_bytes.size(); - - return true; -} - -bool EncTool::GetAesGcmKey(const std::vector<uint8_t>& aad, - const std::vector<uint8_t>& iv_bytes, - const std::vector<uint8_t>& key_bytes, - ScopedSECItem& aes_key, ScopedSECItem& params) { - if (iv_bytes.empty()) { - return false; - } - - // GCM params. - CK_GCM_PARAMS* gcm_params = - static_cast<CK_GCM_PARAMS*>(PORT_Malloc(sizeof(struct CK_GCM_PARAMS))); - if (!gcm_params) { - return false; - } - - uint8_t* iv = static_cast<uint8_t*>(PORT_Malloc(iv_bytes.size())); - if (!iv) { - return false; - } - memcpy(iv, iv_bytes.data(), iv_bytes.size()); - gcm_params->pIv = iv; - gcm_params->ulIvLen = iv_bytes.size(); - gcm_params->ulTagBits = 128; - if (aad.empty()) { - gcm_params->pAAD = nullptr; - gcm_params->ulAADLen = 0; - } else { - uint8_t* ad = static_cast<uint8_t*>(PORT_Malloc(aad.size())); - if (!ad) { - return false; - } - memcpy(ad, aad.data(), aad.size()); - gcm_params->pAAD = ad; - gcm_params->ulAADLen = aad.size(); - } - - params = - ScopedSECItem(SECITEM_AllocItem(nullptr, nullptr, sizeof(*gcm_params))); - if (!params) { - return false; - } - params->len = sizeof(*gcm_params); - params->type = siBuffer; - params->data = reinterpret_cast<unsigned char*>(gcm_params); - - return GetKey(key_bytes, aes_key); -} - -bool EncTool::GenerateAesGcmKey(const std::vector<uint8_t>& aad, - ScopedSECItem& aes_key, ScopedSECItem& params) { - size_t key_size = 16, iv_size = 12; - std::vector<uint8_t> iv_bytes = GenerateRandomness(iv_size); - PrintBytes(iv_bytes, "IV"); - std::vector<uint8_t> key_bytes = GenerateRandomness(key_size); - PrintBytes(key_bytes, "key"); - // Maybe write out the key and parameters. - if (write_key_ && !WriteBytes(key_bytes, key_file_)) { - return false; - } - if (write_iv_ && !WriteBytes(iv_bytes, iv_file_)) { - return false; - } - return GetAesGcmKey(aad, iv_bytes, key_bytes, aes_key, params); -} - -bool EncTool::ReadAesGcmKey(const std::vector<uint8_t>& aad, - ScopedSECItem& aes_key, ScopedSECItem& params) { - std::vector<uint8_t> iv_bytes = ReadInputData(iv_file_); - PrintBytes(iv_bytes, "IV"); - std::vector<uint8_t> key_bytes = ReadInputData(key_file_); - PrintBytes(key_bytes, "key"); - return GetAesGcmKey(aad, iv_bytes, key_bytes, aes_key, params); -} - -bool EncTool::GetChachaKey(const std::vector<uint8_t>& aad, - const std::vector<uint8_t>& iv_bytes, - const std::vector<uint8_t>& key_bytes, - ScopedSECItem& chacha_key, ScopedSECItem& params) { - if (iv_bytes.empty()) { - return false; - } - - // AEAD params. - CK_NSS_AEAD_PARAMS* aead_params = static_cast<CK_NSS_AEAD_PARAMS*>( - PORT_Malloc(sizeof(struct CK_NSS_AEAD_PARAMS))); - if (!aead_params) { - return false; - } - - uint8_t* iv = static_cast<uint8_t*>(PORT_Malloc(iv_bytes.size())); - if (!iv) { - return false; - } - memcpy(iv, iv_bytes.data(), iv_bytes.size()); - aead_params->pNonce = iv; - aead_params->ulNonceLen = iv_bytes.size(); - aead_params->ulTagLen = 16; - if (aad.empty()) { - aead_params->pAAD = nullptr; - aead_params->ulAADLen = 0; - } else { - uint8_t* ad = static_cast<uint8_t*>(PORT_Malloc(aad.size())); - if (!ad) { - return false; - } - memcpy(ad, aad.data(), aad.size()); - aead_params->pAAD = ad; - aead_params->ulAADLen = aad.size(); - } - - params = - ScopedSECItem(SECITEM_AllocItem(nullptr, nullptr, sizeof(*aead_params))); - if (!params) { - return false; - } - params->len = sizeof(*aead_params); - params->type = siBuffer; - params->data = reinterpret_cast<unsigned char*>(aead_params); - - return GetKey(key_bytes, chacha_key); -} - -bool EncTool::GenerateChachaKey(const std::vector<uint8_t>& aad, - ScopedSECItem& chacha_key, - ScopedSECItem& params) { - size_t key_size = 32, iv_size = 12; - std::vector<uint8_t> iv_bytes = GenerateRandomness(iv_size); - PrintBytes(iv_bytes, "IV"); - std::vector<uint8_t> key_bytes = GenerateRandomness(key_size); - PrintBytes(key_bytes, "key"); - // Maybe write out the key and parameters. - if (write_key_ && !WriteBytes(key_bytes, key_file_)) { - return false; - } - if (write_iv_ && !WriteBytes(iv_bytes, iv_file_)) { - return false; - } - return GetChachaKey(aad, iv_bytes, key_bytes, chacha_key, params); -} - -bool EncTool::ReadChachaKey(const std::vector<uint8_t>& aad, - ScopedSECItem& chacha_key, ScopedSECItem& params) { - std::vector<uint8_t> iv_bytes = ReadInputData(iv_file_); - PrintBytes(iv_bytes, "IV"); - std::vector<uint8_t> key_bytes = ReadInputData(key_file_); - PrintBytes(key_bytes, "key"); - return GetChachaKey(aad, iv_bytes, key_bytes, chacha_key, params); -} - -bool EncTool::DoCipher(std::string file_name, std::string out_file, - bool encrypt, key_func_t get_params) { - SECStatus rv; - unsigned int outLen = 0, chunkSize = 1024; - char buffer[1040]; - const unsigned char* bufferStart = - reinterpret_cast<const unsigned char*>(buffer); - - ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); - if (!slot) { - PrintError("Unable to find security device", PR_GetError(), __LINE__); - return false; - } - - ScopedSECItem key, params; - if (!(this->*get_params)(std::vector<uint8_t>(), key, params)) { - PrintError("Geting keys and params failed.", __LINE__); - return false; - } - - ScopedPK11SymKey symKey( - PK11_ImportSymKey(slot.get(), cipher_mech_, PK11_OriginUnwrap, - CKA_DECRYPT | CKA_ENCRYPT, key.get(), nullptr)); - if (!symKey) { - PrintError("Failure to import key into NSS", PR_GetError(), __LINE__); - return false; - } - - std::streambuf* buf; - std::ofstream output_file(out_file, std::ios::out | std::ios::binary); - if (!out_file.empty()) { - if (!output_file.good()) { - return false; - } - buf = output_file.rdbuf(); - } else { - buf = std::cout.rdbuf(); - } - std::ostream output(buf); - - // Read from stdin. - if (file_name.empty()) { - std::vector<uint8_t> data = ReadInputData(""); - std::vector<uint8_t> out(data.size() + 16); - SECStatus rv; - if (encrypt) { - rv = PK11_Encrypt(symKey.get(), cipher_mech_, params.get(), out.data(), - &outLen, data.size() + 16, data.data(), data.size()); - } else { - rv = PK11_Decrypt(symKey.get(), cipher_mech_, params.get(), out.data(), - &outLen, data.size() + 16, data.data(), data.size()); - } - if (rv != SECSuccess) { - PrintError(encrypt ? "Error encrypting" : "Error decrypting", - PR_GetError(), __LINE__); - return false; - }; - output.write(reinterpret_cast<char*>(out.data()), outLen); - output.flush(); - if (output_file.good()) { - output_file.close(); - } else { - output << std::endl; - } - - std::cerr << "Done " << (encrypt ? "encrypting" : "decrypting") - << std::endl; - return true; - } - - // Read file from file_name. - std::ifstream input(file_name, std::ios::binary); - if (!input.good()) { - return false; - } - uint8_t out[1040]; - while (input) { - if (encrypt) { - input.read(buffer, chunkSize); - rv = PK11_Encrypt(symKey.get(), cipher_mech_, params.get(), out, &outLen, - chunkSize + 16, bufferStart, input.gcount()); - } else { - // We have to read the tag when decrypting. - input.read(buffer, chunkSize + 16); - rv = PK11_Decrypt(symKey.get(), cipher_mech_, params.get(), out, &outLen, - chunkSize + 16, bufferStart, input.gcount()); - } - if (rv != SECSuccess) { - PrintError(encrypt ? "Error encrypting" : "Error decrypting", - PR_GetError(), __LINE__); - return false; - }; - output.write(reinterpret_cast<const char*>(out), outLen); - output.flush(); - } - if (output_file.good()) { - output_file.close(); - } else { - output << std::endl; - } - std::cerr << "Done " << (encrypt ? "encrypting" : "decrypting") << std::endl; - - return true; -} - -size_t EncTool::PrintFileSize(std::string file_name) { - std::ifstream input(file_name, std::ifstream::ate | std::ifstream::binary); - auto size = input.tellg(); - std::cerr << "Size of file to encrypt: " << size / 1024 / 1024 << " MB" - << std::endl; - return size; -} - -bool EncTool::IsValidCommand(ArgParser arguments) { - // Either encrypt or decrypt is fine. - bool valid = arguments.Has("--encrypt") != arguments.Has("--decrypt"); - // An input file is required for decryption only. - valid &= arguments.Has("--in") || arguments.Has("--encrypt"); - // An output file is required for encryption only. - valid &= arguments.Has("--out") || arguments.Has("--decrypt"); - // Files holding the IV and key are required for decryption. - valid &= arguments.Has("--iv") || arguments.Has("--encrypt"); - valid &= arguments.Has("--key") || arguments.Has("--encrypt"); - // Cipher is always required. - valid &= arguments.Has("--cipher"); - return valid; -} - -bool EncTool::Run(const std::vector<std::string>& arguments) { - ArgParser parser(arguments); - - if (!IsValidCommand(parser)) { - Usage(); - return false; - } - - if (NSS_NoDB_Init(nullptr) != SECSuccess) { - PrintError("NSS initialization failed", PR_GetError(), __LINE__); - return false; - } - - if (parser.Has("--debug")) { - debug_ = 1; - } - if (parser.Has("--iv")) { - iv_file_ = parser.Get("--iv"); - } else { - write_iv_ = false; - } - if (parser.Has("--key")) { - key_file_ = parser.Get("--key"); - } else { - write_key_ = false; - } - - key_func_t get_params; - bool encrypt = parser.Has("--encrypt"); - if (parser.Get("--cipher") == kAESCommand) { - cipher_mech_ = CKM_AES_GCM; - if (encrypt) { - get_params = &EncTool::GenerateAesGcmKey; - } else { - get_params = &EncTool::ReadAesGcmKey; - } - } else if (parser.Get("--cipher") == kChaChaCommand) { - cipher_mech_ = CKM_NSS_CHACHA20_POLY1305; - if (encrypt) { - get_params = &EncTool::GenerateChachaKey; - } else { - get_params = &EncTool::ReadChachaKey; - } - } else { - Usage(); - return false; - } - // Don't write out key and iv when decrypting. - if (!encrypt) { - write_key_ = false; - write_iv_ = false; - } - - std::string input_file = parser.Has("--in") ? parser.Get("--in") : ""; - std::string output_file = parser.Has("--out") ? parser.Get("--out") : ""; - size_t file_size = 0; - if (!input_file.empty()) { - file_size = PrintFileSize(input_file); - } - auto begin = std::chrono::high_resolution_clock::now(); - if (!DoCipher(input_file, output_file, encrypt, get_params)) { - (void)NSS_Shutdown(); - return false; - } - auto end = std::chrono::high_resolution_clock::now(); - auto ns = - std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count(); - auto seconds = ns / 1000000000; - std::cerr << ns << " ns (~" << seconds << " s) and " << std::endl; - std::cerr << "That's approximately " << (double)file_size / ns << " b/ns" - << std::endl; - - if (NSS_Shutdown() != SECSuccess) { - return false; - } - - return true; -} - -void EncTool::Usage() { - std::string const txt = R"~( -Usage: nss encrypt|decrypt --cipher aes|chacha [--in <file>] [--out <file>] - [--key <file>] [--iv <file>] - - --cipher Set the cipher to use. - --cipher aes: Use AES-GCM to encrypt/decrypt. - --cipher chacha: Use ChaCha20/Poly1305 to encrypt/decrypt. - --in The file to encrypt/decrypt. If no file is given, we read - from stdin (only when encrypting). - --out The file to write the ciphertext/plaintext to. If no file - is given we write the plaintext to stdout (only when - decrypting). - --key The file to write the used key to/to read the key - from. Optional parameter. When not given, don't write out - the key. - --iv The file to write the used IV to/to read the IV - from. Optional parameter. When not given, don't write out - the IV. - - Examples: - nss encrypt --cipher aes --iv iv --key key --out ciphertext - nss decrypt --cipher chacha --iv iv --key key --in ciphertex - - Note: This tool overrides files without asking. -)~"; - std::cerr << txt << std::endl; -} |