[root]/ src
/ main.zig
3.0KB
/// mkpw
/// Author: Sebastian Michalk <sebastian.michalk@pm.me>
/// ISC License
/// (c) 2026
const std = @import("std");
const os = @import("os");
const exit = std.process.exit;
const srand = std.crypto.random;
pub var CHARSET = blk: {
var chars: [95]u8 = undefined;
for (0..95) |i| {
chars[i] = 32 + @as(u8, @intCast(i));
}
break :blk chars;
};
pub fn die(comptime fmt: []const u8, args: anytype) noreturn {
const stderr = std.fs.File.stderr().deprecatedWriter();
stderr.print(fmt, args) catch {};
exit(1);
}
pub fn calc_entropy(s: usize) f64 {
const n: f64 = 95.0;
const l: f64 = @floatFromInt(s);
return l * std.math.log2(n);
}
pub fn mkpw(pwlen: u32, buffer: []u8) ![]u8 {
if (pwlen == 0 or pwlen > 256) {
die("mkpw: error: length must be greater than 0 and less or equal 256.\n", .{});
}
const target_len = @as(usize, @intCast(pwlen));
if (target_len > buffer.len) {
die("memcpy\n", .{});
}
var i: usize = 0;
while (i < target_len) : (i += 1) {
const idx = srand.uintLessThan(usize, CHARSET.len);
buffer[i] = CHARSET[idx];
}
return buffer[0..target_len];
}
pub fn printpw(buf: []u8) !void {
// Zig 0.15.1 // TODO different way to print to stdout
const stdout = std.fs.File.stdout().deprecatedWriter();
const entropy: f64 = calc_entropy(buf.len);
try stdout.print("{s}\n", .{buf});
try stdout.print("mkpw: entropy: \x1b[4m{d:.1} bits\x1b[0m.\n", .{entropy});
std.crypto.secureZero(u8, buf);
exit(0);
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
const args = try std.process.argsAlloc(alloc);
defer std.process.argsFree(alloc, args);
var i: usize = 1;
var pwlen: u32 = 10;
var pwbuf = [_]u8{0} ** 256;
if (args.len < 2) {
const pw = try mkpw(pwlen, &pwbuf);
try printpw(pw);
}
while (i < args.len) : (i += 1) {
const arg = args[i];
if (std.mem.eql(u8, arg, "-h") or std.mem.eql(u8, arg, "--help")) {
die("mkpw: usage: -l or --length <uint>\n", .{});
}
if (std.mem.eql(u8, arg, "-l") or std.mem.eql(u8, arg, "--length")) {
i += 1;
if (i >= args.len) {
die("mkpw: error: length requires a value\n", .{});
}
pwlen = std.fmt.parseInt(u32, args[i], 10) catch |err| {
switch (err) {
error.InvalidCharacter => {
die("mkpw: error: '{s}' is not a valid int\n", .{args[i]});
},
error.Overflow => {
die("mkpw: error: number too large or negative number\n", .{});
},
}
exit(1);
};
} else {
die("mkpw: usage: -l or --length <uint>\n", .{});
}
const pw = try mkpw(pwlen, &pwbuf);
try printpw(pw);
}
}