101 lines
3.3 KiB
Zig
101 lines
3.3 KiB
Zig
const std = @import("std");
|
|
const crypto = std.crypto;
|
|
|
|
pub fn main() !void {
|
|
const allocator = std.heap.page_allocator;
|
|
const stdin = std.io.getStdIn().reader();
|
|
var buf: [50]u8 = std.mem.zeroes([50]u8);
|
|
const input = try stdin.readUntilDelimiterOrEof(buf[0..], '\n') orelse return;
|
|
const pwd = std.mem.trimRight(u8, input[0 .. input.len - 1], "\r");
|
|
|
|
var should_encrypt = false;
|
|
var args = try std.process.argsWithAllocator(allocator);
|
|
|
|
_ = args.skip();
|
|
const dir = std.fs.cwd();
|
|
while (args.next()) |arg| {
|
|
if (std.mem.eql(u8, arg, "encrypt")) {
|
|
should_encrypt = true;
|
|
} else if (std.mem.eql(u8, arg, "decrypt")) {
|
|
should_encrypt = false;
|
|
} else {
|
|
if (should_encrypt) {
|
|
var key: [32]u8 = std.mem.zeroes([32]u8);
|
|
var nonce: [24]u8 = undefined;
|
|
crypto.random.bytes(&nonce);
|
|
try crypto.pwhash.argon2.kdf(allocator, &key, pwd, &nonce, crypto.pwhash.argon2.Params.interactive_2id, crypto.pwhash.argon2.Mode.argon2id);
|
|
try encrypt(dir, arg, key, nonce);
|
|
} else {
|
|
try decrypt(allocator, dir, arg, pwd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn decrypt(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8, pwd: []const u8) !void {
|
|
{
|
|
var out_buf: [512]u8 = undefined;
|
|
var in_buf: [512]u8 = undefined;
|
|
var nonce: [24]u8 = undefined;
|
|
var key: [32]u8 = undefined;
|
|
|
|
var file = try dir.openFile(path, .{});
|
|
defer file.close();
|
|
|
|
_ = try file.read(&nonce);
|
|
|
|
try crypto.pwhash.argon2.kdf(allocator, &key, pwd, &nonce, crypto.pwhash.argon2.Params.interactive_2id, crypto.pwhash.argon2.Mode.argon2id);
|
|
var out_file = try dir.createFile(path[0 .. path.len - 4], .{
|
|
.read = true,
|
|
.truncate = true,
|
|
});
|
|
defer out_file.close();
|
|
|
|
var counter: u32 = 0;
|
|
var read: usize = 0;
|
|
while (true) {
|
|
read = try file.read(&in_buf);
|
|
if (read <= 0) {
|
|
break;
|
|
}
|
|
|
|
crypto.stream.chacha.XChaCha20IETF.xor(out_buf[0..read], in_buf[0..read], counter, key, nonce);
|
|
counter += 1;
|
|
_ = try out_file.write(out_buf[0..read]);
|
|
}
|
|
}
|
|
try dir.deleteFile(path);
|
|
}
|
|
|
|
pub fn encrypt(dir: std.fs.Dir, path: []const u8, key: [32]u8, nonce: [24]u8) !void {
|
|
{
|
|
var file = try dir.openFile(path, .{});
|
|
defer file.close();
|
|
var out_buf: [512]u8 = undefined;
|
|
var in_buf: [512]u8 = undefined;
|
|
|
|
// missuse out_buf as buffer for format string
|
|
_ = try std.fmt.bufPrint(out_buf[0 .. path.len + 4], "{s}.cha", .{path});
|
|
var out_file = try dir.createFile(out_buf[0 .. path.len + 4], .{
|
|
.read = true,
|
|
});
|
|
defer out_file.close();
|
|
|
|
_ = try out_file.write(&nonce);
|
|
|
|
var counter: u32 = 0;
|
|
var read: usize = 0;
|
|
while (true) {
|
|
read = try file.read(&in_buf);
|
|
if (read <= 0) {
|
|
break;
|
|
}
|
|
|
|
crypto.stream.chacha.XChaCha20IETF.xor(out_buf[0..read], in_buf[0..read], counter, key, nonce);
|
|
counter += 1;
|
|
_ = try out_file.write(out_buf[0..read]);
|
|
}
|
|
}
|
|
try dir.deleteFile(path);
|
|
}
|