summaryrefslogtreecommitdiff
path: root/nss-tool
diff options
context:
space:
mode:
authorFranziskus Kiefer <franziskuskiefer@gmail.com>2017-04-10 16:06:04 +0200
committerFranziskus Kiefer <franziskuskiefer@gmail.com>2017-04-10 16:06:04 +0200
commitd0ba5a10003afb0667fc7ae8dcb559400099a751 (patch)
tree7a20023d87dd30de926d0703d205bc06f1887be8 /nss-tool
parente122c31f974e40a58d7f8940357df709137ae6cc (diff)
downloadnss-hg-d0ba5a10003afb0667fc7ae8dcb559400099a751.tar.gz
Bug 1355422 - NSS tool for encryption, r=ttaubert
Summary: Command line tool to encrypt files with aes-gcm and chacha. Can also be used to measure performance of the cipher. Reviewers: ttaubert Differential Revision: https://nss-review.dev.mozaws.net/D245
Diffstat (limited to 'nss-tool')
-rw-r--r--nss-tool/common/tool.h20
-rw-r--r--nss-tool/common/util.cc12
-rw-r--r--nss-tool/common/util.h7
-rw-r--r--nss-tool/db/dbtool.cc8
-rw-r--r--nss-tool/db/dbtool.h7
-rw-r--r--nss-tool/enc/enctool.cc464
-rw-r--r--nss-tool/enc/enctool.h62
-rw-r--r--nss-tool/nss_tool.cc30
-rw-r--r--nss-tool/nss_tool.gyp1
9 files changed, 593 insertions, 18 deletions
diff --git a/nss-tool/common/tool.h b/nss-tool/common/tool.h
new file mode 100644
index 000000000..17ebcac29
--- /dev/null
+++ b/nss-tool/common/tool.h
@@ -0,0 +1,20 @@
+/* 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/. */
+
+#ifndef tool_h__
+#define tool_h__
+
+#include <string>
+#include <vector>
+
+class Tool {
+ public:
+ virtual bool Run(const std::vector<std::string>& arguments) = 0;
+ virtual ~Tool() {}
+
+ private:
+ virtual void Usage() = 0;
+};
+
+#endif // tool_h__
diff --git a/nss-tool/common/util.cc b/nss-tool/common/util.cc
index 5b7ed0b9d..e5af2cb8a 100644
--- a/nss-tool/common/util.cc
+++ b/nss-tool/common/util.cc
@@ -74,15 +74,15 @@ static char *GetModulePassword(PK11SlotInfo *slot, int retry, void *arg) {
return nullptr;
}
-static std::vector<char> ReadFromIstream(std::istream &is) {
- std::vector<char> certData;
+static std::vector<uint8_t> ReadFromIstream(std::istream &is) {
+ std::vector<uint8_t> data;
while (is) {
char buf[1024];
is.read(buf, sizeof(buf));
- certData.insert(certData.end(), buf, buf + is.gcount());
+ data.insert(data.end(), buf, buf + is.gcount());
}
- return certData;
+ return data;
}
static std::string GetNewPasswordFromUser(void) {
@@ -181,8 +181,8 @@ std::string StringToHex(const ScopedSECItem &input) {
return ss.str();
}
-std::vector<char> ReadInputData(std::string &dataPath) {
- std::vector<char> data;
+std::vector<uint8_t> ReadInputData(std::string dataPath) {
+ std::vector<uint8_t> data;
if (dataPath.empty()) {
std::cout << "No input file path given, using stdin." << std::endl;
data = ReadFromIstream(std::cin);
diff --git a/nss-tool/common/util.h b/nss-tool/common/util.h
index bfe6dbf70..bc2e297a4 100644
--- a/nss-tool/common/util.h
+++ b/nss-tool/common/util.h
@@ -5,12 +5,17 @@
#ifndef util_h__
#define util_h__
+#include "nspr.h"
#include "scoped_ptrs.h"
#include <secmodt.h>
#include <string>
#include <vector>
+#ifndef PORT_Malloc
+#define PORT_Malloc PR_Malloc
+#endif
+
enum PwDataType { PW_NONE = 0, PW_FROMFILE = 1, PW_PLAINTEXT = 2 };
typedef struct {
PwDataType source;
@@ -21,6 +26,6 @@ bool InitSlotPassword(void);
bool ChangeSlotPassword(void);
bool DBLoginIfNeeded(const ScopedPK11SlotInfo &slot);
std::string StringToHex(const ScopedSECItem &input);
-std::vector<char> ReadInputData(std::string &dataPath);
+std::vector<uint8_t> ReadInputData(std::string dataPath);
#endif // util_h__
diff --git a/nss-tool/db/dbtool.cc b/nss-tool/db/dbtool.cc
index e48cedec8..5bdeec56e 100644
--- a/nss-tool/db/dbtool.cc
+++ b/nss-tool/db/dbtool.cc
@@ -264,10 +264,10 @@ bool DBTool::ImportCertificate(const ArgParser &parser) {
return false;
}
- std::vector<char> certData = ReadInputData(derFilePath);
+ std::vector<uint8_t> certData = ReadInputData(derFilePath);
- ScopedCERTCertificate cert(
- CERT_DecodeCertFromPackage(certData.data(), certData.size()));
+ ScopedCERTCertificate cert(CERT_DecodeCertFromPackage(
+ reinterpret_cast<char *>(certData.data()), certData.size()));
if (cert.get() == nullptr) {
std::cerr << "Error: Could not decode certificate!" << std::endl;
return false;
@@ -379,7 +379,7 @@ bool DBTool::ImportKey(const ArgParser &parser) {
return false;
}
- std::vector<char> privKeyData = ReadInputData(privKeyFilePath);
+ std::vector<uint8_t> privKeyData = ReadInputData(privKeyFilePath);
if (privKeyData.empty()) {
return false;
}
diff --git a/nss-tool/db/dbtool.h b/nss-tool/db/dbtool.h
index 927afa9f8..dd0ef0ace 100644
--- a/nss-tool/db/dbtool.h
+++ b/nss-tool/db/dbtool.h
@@ -8,13 +8,14 @@
#include <string>
#include <vector>
#include "argparse.h"
+#include "tool.h"
-class DBTool {
+class DBTool : public Tool {
public:
- bool Run(const std::vector<std::string>& arguments);
+ bool Run(const std::vector<std::string>& arguments) override;
private:
- void Usage();
+ void Usage() override;
bool PathHasDBFiles(std::string path);
void ListCertificates();
bool ImportCertificate(const ArgParser& parser);
diff --git a/nss-tool/enc/enctool.cc b/nss-tool/enc/enctool.cc
new file mode 100644
index 000000000..0e17931a2
--- /dev/null
+++ b/nss-tool/enc/enctool.cc
@@ -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[chunkSize + 16];
+ 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 SECFailure;
+ }
+
+ ScopedSECItem key, params;
+ if (!(this->*get_params)(std::vector<uint8_t>(), key, params)) {
+ PrintError("Geting keys and params failed.", __LINE__);
+ return SECFailure;
+ }
+
+ 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 SECFailure;
+ }
+
+ 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("");
+ uint8_t out[data.size() + 16];
+ SECStatus rv;
+ if (encrypt) {
+ rv = PK11_Encrypt(symKey.get(), cipher_mech_, params.get(), out, &outLen,
+ data.size() + 16, data.data(), data.size());
+ } else {
+ rv = PK11_Decrypt(symKey.get(), cipher_mech_, params.get(), out, &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), 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[chunkSize + 16];
+ 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;
+}
diff --git a/nss-tool/enc/enctool.h b/nss-tool/enc/enctool.h
new file mode 100644
index 000000000..5a6a5a164
--- /dev/null
+++ b/nss-tool/enc/enctool.h
@@ -0,0 +1,62 @@
+/* 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/. */
+
+#ifndef enctool_h__
+#define enctool_h__
+
+#include <string>
+#include <vector>
+#include "argparse.h"
+#include "prerror.h"
+#include "scoped_ptrs.h"
+#include "tool.h"
+
+class EncTool : public Tool {
+ public:
+ bool Run(const std::vector<std::string>& arguments) override;
+ void Usage() override;
+
+ private:
+ typedef bool (EncTool::*key_func_t)(const std::vector<uint8_t>& aad,
+ ScopedSECItem& chacha_key,
+ ScopedSECItem& params);
+ void PrintBytes(const std::vector<uint8_t>& bytes, const std::string& txt);
+ bool WriteBytes(const std::vector<uint8_t>& bytes, std::string out_file);
+ void PrintError(const std::string& m, PRErrorCode err, size_t line_number);
+ void PrintError(const std::string& m, size_t line_number);
+ bool GetKey(const std::vector<uint8_t>& key_bytes, ScopedSECItem& key_item);
+ bool 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);
+ bool 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);
+ bool GenerateAesGcmKey(const std::vector<uint8_t>& aad,
+ ScopedSECItem& aes_key, ScopedSECItem& params);
+ bool ReadAesGcmKey(const std::vector<uint8_t>& aad, ScopedSECItem& aes_key,
+ ScopedSECItem& params);
+ std::vector<uint8_t> GenerateRandomness(size_t num_bytes);
+ bool GenerateChachaKey(const std::vector<uint8_t>& aad,
+ ScopedSECItem& chacha_key, ScopedSECItem& params);
+ bool ReadChachaKey(const std::vector<uint8_t>& aad, ScopedSECItem& chacha_key,
+ ScopedSECItem& params);
+ bool DoCipher(std::string fileName, std::string outFile, bool encrypt,
+ key_func_t get_params);
+ size_t PrintFileSize(std::string fileName);
+ bool IsValidCommand(ArgParser arguments);
+
+ bool debug_ = false;
+ bool write_key_ = true;
+ bool write_iv_ = true;
+ std::string key_file_ = "/tmp/key";
+ std::string iv_file_ = "/tmp/iv";
+ CK_MECHANISM_TYPE cipher_mech_;
+
+ const std::string kAESCommand = "aes";
+ const std::string kChaChaCommand = "chacha";
+};
+
+#endif // enctool_h__
diff --git a/nss-tool/nss_tool.cc b/nss-tool/nss_tool.cc
index 0b6b734bb..1d8fc6153 100644
--- a/nss-tool/nss_tool.cc
+++ b/nss-tool/nss_tool.cc
@@ -2,7 +2,10 @@
* 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 <algorithm>
+#include <cstring>
#include <iostream>
+#include <memory>
#include <string>
#include <vector>
@@ -10,19 +13,40 @@
#include "argparse.h"
#include "db/dbtool.h"
+#include "enc/enctool.h"
+#include "tool.h"
static void Usage() {
std::cerr << "Usage: nss <command> <subcommand> [options]" << std::endl;
std::cerr << " nss db [--path <directory>] <commands>" << std::endl;
+ std::cerr << " nss encrypt <options>" << std::endl;
+ std::cerr << " nss decrypt <options>" << std::endl;
}
+static const std::string kDbCommand = "db";
+static const std::string kEncryptCommand = "encrypt";
+static const std::string kDecryptCommand = "decrypt";
+
int main(int argc, char **argv) {
if (argc < 2) {
Usage();
return 1;
}
+ std::vector<std::string> arguments(argv + 2, argv + argc);
- if (std::string(argv[1]) != "db") {
+ std::unique_ptr<Tool> tool = nullptr;
+ if (argv[1] == kDbCommand) {
+ tool = std::unique_ptr<Tool>(new DBTool());
+ }
+ if (argv[1] == kEncryptCommand) {
+ tool = std::unique_ptr<Tool>(new EncTool());
+ arguments.push_back("--encrypt");
+ }
+ if (argv[1] == kDecryptCommand) {
+ tool = std::unique_ptr<Tool>(new EncTool());
+ arguments.push_back("--decrypt");
+ }
+ if (!tool) {
Usage();
return 1;
}
@@ -30,9 +54,7 @@ int main(int argc, char **argv) {
int exit_code = 0;
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
- std::vector<std::string> arguments(argv + 2, argv + argc);
- DBTool tool;
- if (!tool.Run(arguments)) {
+ if (!tool->Run(arguments)) {
exit_code = 1;
}
diff --git a/nss-tool/nss_tool.gyp b/nss-tool/nss_tool.gyp
index 95b627070..ed408e9b6 100644
--- a/nss-tool/nss_tool.gyp
+++ b/nss-tool/nss_tool.gyp
@@ -15,6 +15,7 @@
'common/argparse.cc',
'common/util.cc',
'db/dbtool.cc',
+ 'enc/enctool.cc',
],
'include_dirs': [
'common',