DenisBytes/zig-jks
Pure Zig implementation of Java KeyStore (JKS) encoder/decoder. Read/write JKS files with zero dependencies. Compatible with Java's keytool.
A Zig implementation of the Java KeyStore (JKS) format encoder/decoder.
zig-jks is a pure Zig library for reading and writing Java KeyStore files in the JKS format. This library provides a complete implementation compatible with the Java KeyStore specification, allowing you to manage cryptographic keys and certificates from Zig applications.
Add this to your build.zig.zon:
.dependencies = .{
.zig_jks = .{
.url = "https://github.com/yourusername/zig-jks/archive/main.tar.gz",
.hash = "...",
},
},
And in your build.zig:
const zig_jks = b.dependency("zig_jks", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zig_jks", zig_jks.module("zig_jks"));
const std = @import("std");
const jks = @import("zig_jks");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Create a new keystore
var keystore = jks.KeyStore.init(allocator);
defer keystore.deinit();
// Add a trusted certificate
const cert = jks.Certificate{
.type = "X509",
.content = certificate_der_bytes,
};
const entry = jks.TrustedCertificateEntry{
.creation_time = std.time.milliTimestamp(),
.certificate = cert,
};
try keystore.setTrustedCertificateEntry("my-cert", entry);
// Save to file
const file = try std.fs.cwd().createFile("keystore.jks", .{});
defer file.close();
try keystore.store(file.writer().any(), "storepassword");
}
const file = try std.fs.cwd().openFile("keystore.jks", .{});
defer file.close();
var keystore = jks.KeyStore.init(allocator);
defer keystore.deinit();
try keystore.load(file.reader().any(), "storepassword");
// Retrieve a certificate
const cert_entry = try keystore.getTrustedCertificateEntry("my-cert");
defer cert_entry.deinit(allocator);
std.debug.print("Certificate type: {s}\n", .{cert_entry.certificate.type});
// Add a private key entry
const chain = [_]jks.Certificate{cert};
const pk_entry = jks.PrivateKeyEntry{
.creation_time = std.time.milliTimestamp(),
.private_key = pkcs8_key_bytes,
.certificate_chain = &chain,
};
try keystore.setPrivateKeyEntry("my-key", pk_entry, "keypassword");
// Retrieve and decrypt the private key
const retrieved = try keystore.getPrivateKeyEntry("my-key", "keypassword");
defer retrieved.deinit(allocator);
// Use the decrypted private key
std.debug.print("Private key size: {d} bytes\n", .{retrieved.private_key.len});
const options = jks.KeyStoreOptions{
.ordered = true, // Sort aliases alphabetically
.case_exact = true, // Preserve alias case (default: lowercase)
.min_password_len = 8, // Minimum password length
};
var keystore = jks.KeyStore.initWithOptions(allocator, options);
defer keystore.deinit();
init(allocator) - Create a new keystore with default optionsinitWithOptions(allocator, options) - Create with custom optionsdeinit() - Free all resourcessetPrivateKeyEntry(alias, entry, password) - Add a private key entrygetPrivateKeyEntry(alias, password) - Retrieve and decrypt a private key entrysetTrustedCertificateEntry(alias, entry) - Add a trusted certificategetTrustedCertificateEntry(alias) - Retrieve a trusted certificatedeleteEntry(alias) - Remove an entryaliases() - Get list of all aliasesstore(writer, password) - Write keystore to a writerload(reader, password) - Read keystore from a readerCertificate - X.509 or other certificate typePrivateKeyEntry - Private key with certificate chainTrustedCertificateEntry - Standalone trusted certificatedeinit()The examples/ directory contains practical demonstrations:
See examples/README.md for detailed instructions.
The testdata/ directory contains various JKS files for testing:
# Generate all test files
zig build generate-testdata
This creates keystores with:
See testdata/README.md for details on each test file.
Run the test suite:
zig build test
This implementation is compatible with Java KeyStore files created by:
keytool utilityjava.security.KeyStore APIThis project is released under the MIT License. See LICENSE file for details.
Contributions are welcome! Please feel free to submit issues or pull requests.