Files
envr/zig-vendor/age-ffi/zig/example.zig
2026-06-16 12:00:41 -04:00

195 lines
7.6 KiB
Zig

//! Example usage of the age-ffi Zig bindings
//!
//! This file demonstrates various encryption/decryption operations using the age library.
const std = @import("std");
const age = @import("age.zig");
pub fn main(init: std.process.Init) !void {
const gpa = init.gpa;
const io = init.io;
// Set up unbuffered stdout for Zig 0.15+ (simpler for examples)
// var stdout_writer = std.fs.File.stdout().writer(&.{});
var stdout_writer = std.Io.File.stdout().writer(io, &.{});
const stdout = &stdout_writer.interface;
try stdout.print("age-ffi Zig Bindings Example\n", .{});
try stdout.print("============================\n\n", .{});
// Print version information
try stdout.print("Library version: {s}\n", .{age.getVersion()});
try stdout.print("Age library version: {s}\n\n", .{age.getLibVersion()});
// Example 1: Generate a keypair
try stdout.print("Example 1: Generating a keypair\n", .{});
try stdout.print("--------------------------------\n", .{});
var keypair = try age.generateKeypair();
defer keypair.deinit();
try stdout.print("Public key: {s}\n", .{keypair.getPublicKey()});
try stdout.print("Private key: {s}\n\n", .{keypair.getPrivateKey()});
try stdout.flush();
// Example 2: Simple encryption and decryption
try stdout.print("Example 2: Simple encryption/decryption\n", .{});
try stdout.print("---------------------------------------\n", .{});
const plaintext = "Hello, World! This is a secret message.";
try stdout.print("Original: {s}\n", .{plaintext});
// Encrypt
var encrypted = try age.encrypt(plaintext, keypair.getPublicKey());
defer encrypted.deinit();
try stdout.print("Encrypted: {} bytes\n", .{encrypted.buffer.len});
// Decrypt
var decrypted = try age.decrypt(encrypted.toSlice(), keypair.getPrivateKey());
defer decrypted.deinit();
try stdout.print("Decrypted: {s}\n\n", .{decrypted.toSlice()});
try stdout.flush();
// Example 3: ASCII armor
try stdout.print("Example 3: ASCII armor encryption\n", .{});
try stdout.print("----------------------------------\n", .{});
var armored = try age.encryptArmor("This message will be ASCII armored.", keypair.getPublicKey());
defer armored.deinit();
try stdout.print("Encrypted with ASCII armor: {} bytes\n", .{armored.buffer.len});
// Decrypt armored message
var decrypted_armored = try age.decrypt(armored.toSlice(), keypair.getPrivateKey());
defer decrypted_armored.deinit();
try stdout.print("Decrypted successfully: {s}\n\n", .{decrypted_armored.toSlice()});
try stdout.flush();
// Example 4: Passphrase-based encryption
try stdout.print("Example 4: Passphrase encryption\n", .{});
try stdout.print("---------------------------------\n", .{});
const passphrase = "super-secret-passphrase";
const secret_data = "Encrypted with a passphrase!";
// Encrypt without armor (armor with passphrase has decryption issues in upstream library)
var pass_encrypted = try age.encryptPassphrase(secret_data, passphrase, false);
defer pass_encrypted.deinit();
try stdout.print("Passphrase-encrypted: {} bytes\n", .{pass_encrypted.buffer.len});
var pass_decrypted = try age.decryptPassphrase(pass_encrypted.toSlice(), passphrase);
defer pass_decrypted.deinit();
try stdout.print("Decrypted: {s}\n\n", .{pass_decrypted.toSlice()});
try stdout.flush();
// Example 5: Multiple recipients
try stdout.print("Example 5: Multiple recipients\n", .{});
try stdout.print("-------------------------------\n", .{});
// Generate a second keypair
var keypair2 = try age.generateKeypair();
defer keypair2.deinit();
try stdout.print("Recipient 1: {s}\n", .{keypair.getPublicKey()});
try stdout.print("Recipient 2: {s}\n", .{keypair2.getPublicKey()});
// Create array of recipients
const recipients = [_][:0]const u8{
keypair.getPublicKey(),
keypair2.getPublicKey(),
};
const multi_plaintext = "This can be decrypted by either recipient!";
var multi_encrypted = try age.encryptMulti(multi_plaintext, &recipients, false);
defer multi_encrypted.deinit();
try stdout.print("Encrypted for both recipients ({} bytes)\n", .{multi_encrypted.buffer.len});
// Decrypt with first identity
var multi_decrypted1 = try age.decrypt(multi_encrypted.toSlice(), keypair.getPrivateKey());
defer multi_decrypted1.deinit();
try stdout.print("Decrypted with key 1: {s}\n", .{multi_decrypted1.toSlice()});
// Decrypt with second identity
var multi_decrypted2 = try age.decrypt(multi_encrypted.toSlice(), keypair2.getPrivateKey());
defer multi_decrypted2.deinit();
try stdout.print("Decrypted with key 2: {s}\n\n", .{multi_decrypted2.toSlice()});
try stdout.flush();
// Example 6: File operations
try stdout.print("Example 6: File encryption/decryption\n", .{});
try stdout.print("--------------------------------------\n", .{});
const file_data = "This will be written to an encrypted file.";
const encrypted_file = "/tmp/test.age";
// Encrypt to file (non-armored)
try age.encryptToFile(file_data, keypair.getPublicKey(), encrypted_file);
try stdout.print("Encrypted to file: {s}\n", .{encrypted_file});
// Decrypt from file
var file_decrypted = try age.decryptFileWithIdentity(encrypted_file, keypair.getPrivateKey());
defer file_decrypted.deinit();
try stdout.print("Decrypted from file: {s}\n\n", .{file_decrypted.toSlice()});
try stdout.flush();
// Example 7: Validation
try stdout.print("Example 7: Key validation\n", .{});
try stdout.print("--------------------------\n", .{});
const valid_recipient = keypair.getPublicKey();
const valid_identity = keypair.getPrivateKey();
const invalid_key = "not-a-valid-key";
try stdout.print("Is '{s}' a valid recipient? {}\n", .{ valid_recipient, age.isValidX25519Recipient(valid_recipient) });
try stdout.print("Is '{s}' a valid identity? {}\n", .{ valid_identity, age.isValidX25519Identity(valid_identity) });
try stdout.print("Is '{s}' a valid recipient? {}\n", .{ invalid_key, age.isValidX25519Recipient(invalid_key) });
const recipient_type = age.getRecipientType(valid_recipient);
try stdout.print("Recipient type: {s}\n\n", .{@tagName(recipient_type)});
try stdout.flush();
// Example 8: Deriving public key from private key
try stdout.print("Example 8: Derive public key\n", .{});
try stdout.print("-----------------------------\n", .{});
const derived_public = try age.derivePublicKey(gpa, keypair.getPrivateKey());
defer gpa.free(derived_public);
try stdout.print("Original public: {s}\n", .{keypair.getPublicKey()});
try stdout.print("Derived public: {s}\n", .{derived_public});
try stdout.print("Keys match: {}\n\n", .{std.mem.eql(u8, keypair.getPublicKey(), derived_public)});
try stdout.flush();
// Example 9: Error handling
try stdout.print("Example 9: Error handling\n", .{});
try stdout.print("-------------------------\n", .{});
// Try to decrypt with wrong key
if (age.decrypt(encrypted.toSlice(), keypair2.getPrivateKey())) |_| {
try stdout.print("Unexpected success!\n", .{});
} else |err| {
try stdout.print("Expected error: {s}\n", .{@errorName(err)});
}
// Try to use invalid passphrase
if (age.decryptPassphrase(pass_encrypted.toSlice(), "wrong-passphrase")) |_| {
try stdout.print("Unexpected success!\n", .{});
} else |err| {
try stdout.print("Expected error: {s}\n", .{@errorName(err)});
}
try stdout.print("\nAll examples completed successfully!\n", .{});
// Flush all output to ensure it's displayed
try stdout.flush();
}