add credential generation
This commit is contained in:
parent
d4911b3bc1
commit
4b0284a778
87
build.zig
87
build.zig
|
@ -89,4 +89,91 @@ pub fn build(b: *std.Build) !void {
|
|||
cs.addIncludePath(.{ .path = "c" });
|
||||
cs.linkLibrary(sqlite_dep.artifact("sqlite"));
|
||||
}
|
||||
|
||||
var creds_step = b.step("generate_credentials", "Generate credentials for access_keys.csv");
|
||||
creds_step.makeFn = generateCredentials;
|
||||
}
|
||||
|
||||
fn generateCredentials(s: *std.build.Step, prog_node: *std.Progress.Node) error{ MakeFailed, MakeSkipped }!void {
|
||||
// Format:
|
||||
// Access Key,Account Id,Existing encoded encryption key, New encoded encryption
|
||||
_ = prog_node;
|
||||
const encryption = @import("src/encryption.zig");
|
||||
var key: [encryption.encoded_key_length]u8 = undefined;
|
||||
encryption.randomEncodedKey(&key);
|
||||
|
||||
const seed = @as(u64, @truncate(@as(u128, @bitCast(std.time.nanoTimestamp()))));
|
||||
var prng = std.rand.DefaultPrng.init(seed);
|
||||
var rand = prng.random();
|
||||
const account_number = rand.intRangeAtMost(u64, 100000000000, 999999999999);
|
||||
const access_key_suffix: u128 = blk: { // workaround for u64 max on rand.intRangeAtMost
|
||||
const min = 0xECFF3BCC40CA2000000000;
|
||||
// const max = 0x2153E468B91C6E0000000000;
|
||||
// const diff = max - min; // 0x2066e52cecdba40000000000 (is 12 bytes/96 bits)
|
||||
// So we can use a full 64 bit range and just add to the min
|
||||
break :blk @as(u128, rand.int(u64)) + min;
|
||||
};
|
||||
const access_key_suffix_encoded = encode(
|
||||
u128,
|
||||
s.owner.allocator,
|
||||
access_key_suffix,
|
||||
) catch return error.MakeFailed;
|
||||
var secret_key: [30]u8 = undefined;
|
||||
rand.bytes(&secret_key); // The rest don't need to be cryptographically secure...does this?
|
||||
var encoded_secret: [40]u8 = undefined;
|
||||
_ = std.base64.standard.Encoder.encode(&encoded_secret, secret_key[0..]);
|
||||
|
||||
std.debug.print(
|
||||
"access_key: EL{s}, secret_key: {s}, account_number: {d}, db_encryption_key: {s}",
|
||||
.{
|
||||
access_key_suffix_encoded,
|
||||
encoded_secret,
|
||||
account_number,
|
||||
key,
|
||||
},
|
||||
);
|
||||
// Documentation describes account id as a 12 digit number:
|
||||
// https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-identifiers.html
|
||||
// Random u64
|
||||
// Max: 0x3b9ac9ff (0d999999999)
|
||||
// Min: 0x05f5e100 (0d100000000)
|
||||
//
|
||||
// Access key and secret key are probably more loose. Here is one:
|
||||
//
|
||||
// "AccessKey": {
|
||||
// "AccessKeyId": "AKIAYAM4POHXNMQUDBNG",
|
||||
// "SecretAccessKey": "CQwhFQlaSiI/N1sHsNgLyFsOXOBXbzUNQcmU4udL",
|
||||
// }
|
||||
// Access key appears 20 characters A-Z, 0-9. Starts with AK or AS, so
|
||||
// 18 characters of random, and it looks like base36
|
||||
// https://ziglang.org/documentation/0.11.0/std/src/std/base64.zig.html
|
||||
// https://en.wikipedia.org/wiki/Base36
|
||||
// For 18 characters, the lower end would be:
|
||||
// NN100000000000000000 (hex: ECFF3BCC40CA2000000000)
|
||||
// Upper:
|
||||
// NNZZZZZZZZZZZZZZZZZZ (hex: 2153E468B91C6E0000000000)
|
||||
// Which can be stored in u24
|
||||
// Secret key here is 40 characters and roughly looks like base64 encoded
|
||||
// random binary data, which it probably is. 40 characters of base64 is 32 bytes of data
|
||||
}
|
||||
|
||||
/// encodes an unsigned integer into base36
|
||||
pub fn encode(comptime T: type, allocator: std.mem.Allocator, data: T) ![]const u8 {
|
||||
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const ti = @typeInfo(T);
|
||||
if (ti != .Int or ti.Int.signedness != .unsigned)
|
||||
@compileError("encode only works with unsigned integers");
|
||||
const bits = ti.Int.bits;
|
||||
// We cannot have more than 6 bits (2^6 = 64) represented per byte in our final output
|
||||
var al = try std.ArrayList(u8).initCapacity(allocator, bits / 6);
|
||||
defer al.deinit();
|
||||
|
||||
var remaining = data;
|
||||
while (remaining > 0) : (remaining /= 36) {
|
||||
al.appendAssumeCapacity(alphabet[@as(usize, @intCast(remaining % 36))]);
|
||||
}
|
||||
// This is not exact, but 6 bits
|
||||
var rc = try al.toOwnedSlice();
|
||||
std.mem.reverse(u8, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ const sqlite = @import("sqlite"); // TODO: If we use this across all services, A
|
|||
|
||||
const test_account_key = "09aGW6z6QofVsPlWP9FGqVnshxHWAWrKZwLkwkgWs7w=";
|
||||
|
||||
const log = std.log.scoped(.Account);
|
||||
const Self = @This();
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
|
@ -13,7 +14,10 @@ pub fn accountForId(allocator: std.mem.Allocator, account_id: []const u8) !Self
|
|||
// TODO: Allow environment variables to house encoded keys. If not in the
|
||||
// environment, check with LocalDB table to get it. We're
|
||||
// building LocalDB, though, so we need that working first...
|
||||
if (!std.mem.eql(u8, account_id, "1234")) return error.NotImplemented;
|
||||
if (!std.mem.eql(u8, account_id, "1234")) {
|
||||
log.err("Got account id '{s}', but only '1234' is valid right now", .{account_id});
|
||||
return error.NotImplemented;
|
||||
}
|
||||
var key = try allocator.alloc(u8, encryption.key_length);
|
||||
errdefer allocator.free(key);
|
||||
try encryption.decodeKey(key[0..encryption.key_length], test_account_key.*);
|
||||
|
|
|
@ -127,8 +127,8 @@ fn getCreds(access: []const u8) ?signing.Credentials {
|
|||
|
||||
fn accountForAccessKey(allocator: std.mem.Allocator, access_key: []const u8) ![]const u8 {
|
||||
_ = allocator;
|
||||
_ = access_key;
|
||||
return "1234, Get your woman, on the floor";
|
||||
log.debug("Finding account for access key: '{s}'", .{access_key});
|
||||
return "1234";
|
||||
}
|
||||
/// Function assumes an authenticated request, so signing.verify must be called
|
||||
/// and returned true before calling this function. If authentication header
|
||||
|
|
Loading…
Reference in New Issue
Block a user