#include #include #include #include #include #include #include "velvet_ring.h" bool is_ascii(const std::string& str) { return std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isprint(c) || c == '\n' || c == '\r' || c == '\t'; }); } using ByteVec = std::vector; ByteVec read_file(const std::string path) { std::ifstream f(path, std::ios::binary); if (!f) throw std::runtime_error("failed to open: " + path); return ByteVec((std::istreambuf_iterator(f)), std::istreambuf_iterator()); } void write_file(const std::string path, const ByteVec data) { std::ofstream f(path, std::ios::binary); if (!f) throw std::runtime_error("failed to write: " + path); f.write(reinterpret_cast(data.data()), data.size()); } bool ends_with(const std::string s, const std::string suf) { return s.size() >= suf.size() && s.compare(s.size() - suf.size(), suf.size(), suf) == 0; } std::string enc_out(const std::string in) { return in + ".vvt"; } std::string dec_out(const std::string in) { if (ends_with(in, ".vvt")) return in.substr(0, in.size() - 4); return in + ".dec"; } std::string ring_name(const std::string& enc) { return enc + ".ring"; } std::string get_opt(int argc, char* argv[], const std::string opt) { for (int i = 3; i < argc - 1; ++i) if (argv[i] == opt) return argv[i + 1]; return ""; } std::string help = R"(love is a gentle thing(lx) by maki v1.0 usage: ec-pass -p [-o ] dec-pass -p [-o ] ec-key [-o ] dec-key [-o ])"; void usage() { std::cout << help << "\n"; } int main(int argc, char* argv[]) { if (argc < 3) { int retcode = 1; if (argc == 1) retcode = 0; usage(); return retcode; } std::string mode = argv[1]; std::string in = argv[2]; std::string out = get_opt(argc, argv, "-o"); std::string pass = get_opt(argc, argv, "-p"); try { ByteVec input = read_file(in); // using key (ring) if (mode == "ec-key") { if (out.empty()) out = enc_out(in); std::string ring = ring_name(out); ByteVec key = rb(32); ByteVec enc = ec_wky( std::string(input.begin(), input.end()), key ); write_file(out, enc); write_file(ring, key); std::cout << "encrypted file: " << out << "\n"; std::cout << "key ring: " << ring << "\n"; } else if (mode == "dec-key") { if (out.empty()) out = dec_out(in); std::string ring = ring_name(in); ByteVec key = read_file(ring); if (key.size() != 32) throw std::runtime_error("invalid ring file!"); std::string dec = dec_wky(input, key); write_file(out, ByteVec(dec.begin(), dec.end())); if (is_ascii(dec)) std::cout << dec; //std::cout << "Decrypted " << out << "\n"; } // using pass else if (mode == "ec-pass") { if (pass.empty()) throw std::runtime_error("missing password! provide one using -p ."); if (out.empty()) out = enc_out(in); ByteVec enc = ec_p( std::string(input.begin(), input.end()), pass ); write_file(out, enc); std::cout << "encrypted file: " << out << "\n"; } else if (mode == "dec-pass") { if (pass.empty()) throw std::runtime_error("missing password! provide one using -p ."); if (out.empty()) out = dec_out(in); std::string dec = dec_p(input, pass); write_file(out, ByteVec(dec.begin(), dec.end())); if (is_ascii(dec)) { std::cout << dec; } //std::cout << "Decrypted " << out << "\n"; // i think this is redundnant now cuz duh it better be there } else { usage(); return 1; } } catch (const std::exception& e) { std::cerr << "error: " << e.what() << "\n"; return 1; } return 0; }