Skip to content

Commit

Permalink
Merge pull request #1 from r4gus/kdbx
Browse files Browse the repository at this point in the history
Kdbx
  • Loading branch information
r4gus authored Jan 26, 2025
2 parents 827d55b + d34ab9c commit c4a1a17
Show file tree
Hide file tree
Showing 10 changed files with 3,120 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
zig-out
zig-cache
.zig-cache
*.swp
venv
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ This document describes a format to store secrets at rest based on the CBOR data

### Installation

> Requires Zig version 0.13.0
Versions:

| Zig version | ccdb version |
|:-----------:|:------------:|
| 0.13.0 | 0.1.0, 0.2.0 |
| 0.14.0 | 0.3.0 |

#### Module

Expand All @@ -23,6 +28,13 @@ The `ccdb` module can be added to your projects by adding `ccdb` to your list of
},
```

Alternatively you can use the following command, which will automatically add `ccdb` as an dependency to your `build.zig.zon` file:

```bash
# Replace <VERSION TAG> with the version you want to use
zig fetch --save https://github.com/r4gus/ccdb/archive/refs/tags/<VERSION TAG>.tar.gz
```

You can then import the module within your `build.zig`.

```zig
Expand Down
16 changes: 7 additions & 9 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.name = "ccdb",
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.2.0",
.version = "0.3.0",

// This field is optional.
// This is currently advisory only; Zig does not yet do anything
Expand Down Expand Up @@ -44,18 +44,16 @@
// .lazy = false,
//},
.zbor = .{
.url = "https://github.com/r4gus/zbor/archive/refs/tags/0.15.0.tar.gz",
.hash = "12209a78f8c31b6d65d2249082dc824da4a191f6f7be6a1c1740fc093b765c5ebeea",
//.path = "../../zbor",
.url = "https://github.com/r4gus/zbor/archive/refs/tags/0.16.0.tar.gz",
.hash = "12204e296dfd96db337f0b59dbde2bfb9c5e5107be64ef1067087398d4985c8ffc3d",
},
.uuid = .{
.url = "https://github.com/r4gus/uuid-zig/archive/refs/tags/0.2.1.tar.gz",
.hash = "1220b4deeb4ec1ec3493ea934905356384561b725dba69d1fbf6a25cb398716dd05b",
.url = "https://github.com/r4gus/uuid-zig/archive/refs/tags/0.3.0.tar.gz",
.hash = "12207920ff3fce69398afc959b252b8cd72ab55a6dbb251d71fa046a43d9a85bffe6",
},
.clap = .{
.url = "https://github.com/Hejsil/zig-clap/archive/refs/tags/0.9.1.tar.gz",
.hash = "122062d301a203d003547b414237229b09a7980095061697349f8bef41be9c30266b",
//.path = "../ccdb",
.url = "git+https://github.com/Hejsil/zig-clap#068c38f89814079635692c7d0be9f58508c86173",
.hash = "1220ff14a53e9a54311c9b0e665afeda2c82cfd6f57e7e1b90768bf13b85f9f29cd0",
},
},

Expand Down
140 changes: 140 additions & 0 deletions kdbx/chacha.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
const std = @import("std");
const builtin = @import("builtin");
const crypto = std.crypto;
const math = std.math;
const mem = std.mem;
const assert = std.debug.assert;
const testing = std.testing;
const maxInt = math.maxInt;

pub const ChaCha20 = struct {
ctx: BlockVec,
x: BlockVec,
left: usize,
buffer: [64]u8,

const BlockVec = [16]u32;

/// Nonce length in bytes.
pub const nonce_length = 12;
/// Key length in bytes.
pub const key_length = 32;
/// Block length in bytes.
pub const block_length = 64;
pub const rounds_nb = 20;

pub fn init(counter: u32, key_: [key_length]u8, nonce: [nonce_length]u8) @This() {
var d: [4]u32 = undefined;
d[0] = counter;
d[1] = mem.readInt(u32, nonce[0..4], .little);
d[2] = mem.readInt(u32, nonce[4..8], .little);
d[3] = mem.readInt(u32, nonce[8..12], .little);

const key = keyToWords(key_);

const c = "expand 32-byte k";
const constant_le = comptime [4]u32{
mem.readInt(u32, c[0..4], .little),
mem.readInt(u32, c[4..8], .little),
mem.readInt(u32, c[8..12], .little),
mem.readInt(u32, c[12..16], .little),
};
return .{
.ctx = .{
constant_le[0], constant_le[1], constant_le[2], constant_le[3],
key[0], key[1], key[2], key[3],
key[4], key[5], key[6], key[7],
d[0], d[1], d[2], d[3],
},
.x = .{0} ** 16,
.left = 0,
.buffer = undefined,
};
}

pub fn xor(self: *@This(), out: []u8) void {
var k: usize = 0;

while (k < out.len) {
if (self.left == 0) {
chacha20Core(self.x[0..], self.ctx);
contextFeedback(&self.x, self.ctx);
hashToBytes(self.buffer[0..64], self.x);
self.left = 64;
self.ctx[12] +%= 1;
}

out[k] ^= self.buffer[64 - self.left];
k += 1;
self.left -= 1;
}
}

const QuarterRound = struct {
a: usize,
b: usize,
c: usize,
d: usize,
};

fn Rp(a: usize, b: usize, c: usize, d: usize) QuarterRound {
return QuarterRound{
.a = a,
.b = b,
.c = c,
.d = d,
};
}

inline fn chacha20Core(x: *BlockVec, input: BlockVec) void {
x.* = input;

const rounds = comptime [_]QuarterRound{
Rp(0, 4, 8, 12),
Rp(1, 5, 9, 13),
Rp(2, 6, 10, 14),
Rp(3, 7, 11, 15),
Rp(0, 5, 10, 15),
Rp(1, 6, 11, 12),
Rp(2, 7, 8, 13),
Rp(3, 4, 9, 14),
};

comptime var j: usize = 0;
inline while (j < rounds_nb) : (j += 2) {
inline for (rounds) |r| {
x[r.a] +%= x[r.b];
x[r.d] = math.rotl(u32, x[r.d] ^ x[r.a], @as(u32, 16));
x[r.c] +%= x[r.d];
x[r.b] = math.rotl(u32, x[r.b] ^ x[r.c], @as(u32, 12));
x[r.a] +%= x[r.b];
x[r.d] = math.rotl(u32, x[r.d] ^ x[r.a], @as(u32, 8));
x[r.c] +%= x[r.d];
x[r.b] = math.rotl(u32, x[r.b] ^ x[r.c], @as(u32, 7));
}
}
}

inline fn hashToBytes(out: *[64]u8, x: BlockVec) void {
for (0..4) |i| {
mem.writeInt(u32, out[16 * i + 0 ..][0..4], x[i * 4 + 0], .little);
mem.writeInt(u32, out[16 * i + 4 ..][0..4], x[i * 4 + 1], .little);
mem.writeInt(u32, out[16 * i + 8 ..][0..4], x[i * 4 + 2], .little);
mem.writeInt(u32, out[16 * i + 12 ..][0..4], x[i * 4 + 3], .little);
}
}

inline fn contextFeedback(x: *BlockVec, ctx: BlockVec) void {
for (0..16) |i| {
x[i] +%= ctx[i];
}
}
};

fn keyToWords(key: [32]u8) [8]u32 {
var k: [8]u32 = undefined;
for (0..8) |i| {
k[i] = mem.readInt(u32, key[i * 4 ..][0..4], .little);
}
return k;
}
Loading

0 comments on commit c4a1a17

Please sign in to comment.