// =============================================================================
// Std::Crypto::Aes — AES-256-CBC and AES-256-GCM encryption/decryption
// =============================================================================
module Std::Crypto::Aes {

    import Std::Mem::{Alloc, Free};
    import Std::String::{String_Len};

    extern func bux_random_bytes(buf: *void, len: int) -> int;
    extern func bux_aes_256_cbc_encrypt(plain: String, plainlen: int, key: String, iv: String, outlen: *int) -> String;
    extern func bux_aes_256_cbc_decrypt(cipher: String, cipherlen: int, key: String, iv: String, outlen: *int) -> String;
    extern func bux_aes_256_gcm_encrypt(plain: String, plainlen: int, key: String, iv: String, tag: *void, outlen: *int) -> String;
    extern func bux_aes_256_gcm_decrypt(cipher: String, cipherlen: int, key: String, iv: String, tag: String, outlen: *int) -> String;

    // --- AES-256-CBC ---

    const AES_KEY_SIZE: int = 32;  // 256 bits
    const AES_IV_SIZE: int  = 16;  // 128 bits
    const AES_GCM_TAG_SIZE: int = 16;

    // Generate a random 256-bit AES key (returns raw 32 bytes)
    func Aes_GenerateKey() -> String {
        let buf: *void = Alloc(AES_KEY_SIZE as uint);
        if bux_random_bytes(buf, AES_KEY_SIZE) != 1 {
            Free(buf);
            return "";
        }
        return buf as String;
    }

    // Generate a random 128-bit IV (returns raw 16 bytes)
    func Aes_GenerateIV() -> String {
        let buf: *void = Alloc(AES_IV_SIZE as uint);
        if bux_random_bytes(buf, AES_IV_SIZE) != 1 {
            Free(buf);
            return "";
        }
        return buf as String;
    }

    // AES-256-CBC encrypt. plain and key are binary strings, iv is 16 bytes.
    // Returns ciphertext (may be longer than plain due to PKCS#7 padding).
    func Aes_CbcEncrypt(plain: String, key: String, iv: String) -> String {
        let outlen: int = 0;
        return bux_aes_256_cbc_encrypt(plain, String_Len(plain) as int, key, iv, &outlen);
    }

    // AES-256-CBC decrypt. Returns plaintext.
    func Aes_CbcDecrypt(cipher: String, key: String, iv: String) -> String {
        let outlen: int = 0;
        return bux_aes_256_cbc_decrypt(cipher, String_Len(cipher) as int, key, iv, &outlen);
    }

    // --- AES-256-GCM (Authenticated Encryption) ---

    // AES-256-GCM encrypt. Returns ciphertext. tag receives 16-byte authentication tag.
    func Aes_GcmEncrypt(plain: String, key: String, iv: String, tag: *void) -> String {
        let outlen: int = 0;
        return bux_aes_256_gcm_encrypt(plain, String_Len(plain) as int, key, iv, tag, &outlen);
    }

    // AES-256-GCM decrypt. Returns plaintext. tag must be the 16-byte auth tag from encryption.
    func Aes_GcmDecrypt(cipher: String, key: String, iv: String, tag: String) -> String {
        let outlen: int = 0;
        return bux_aes_256_gcm_decrypt(cipher, String_Len(cipher) as int, key, iv, tag, &outlen);
    }
}
