mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-21 07:47:32 +09:00
Update NSS to 3.35-RTM
This commit is contained in:
parent
fe49ad404e
commit
66dd670b60
388 changed files with 39075 additions and 20752 deletions
464
security/nss/nss-tool/enc/enctool.cc
Normal file
464
security/nss/nss-tool/enc/enctool.cc
Normal file
|
|
@ -0,0 +1,464 @@
|
|||
/* 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue