Skip to content

K9Crypt/k9crypt-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

K9Crypt Go Banner

K9Crypt Go

K9Crypt Go is a production-focused encryption module with a V5 AEAD payload format, authenticated metadata, cipher selection (AES-256-GCM / ChaCha20-Poly1305), master key derivation with HKDF expansion, bounded batch processing, and safe defaults for low-latency application encryption.

Key Features

  • V5 AEAD format - single-pass authenticated encryption with a 19-byte header and 12-byte IV
  • Cipher selection - AES-256-GCM (default) or ChaCha20-Poly1305 via CipherId option
  • Master key + HKDF - PBKDF2 master key derivation with HMAC-SHA512 per-message key expansion
  • Backward compatible - transparently decrypts legacy V1-V4 payloads
  • Authenticated metadata - magic, version, flags, cipher ID, time step, and issue time bound to ciphertext via AAD
  • Freshness validation - optional max-age and clock-skew enforcement on decrypt
  • Batch operations - sequential and parallel batch encrypt/decrypt with progress callbacks
  • Compression support - optional zlib compression with configurable level

Payload Format (V5)

header(19) | salt(32) | iv(12) | ciphertext(N) | tag(16) | integritySalt(16) | dataHash(64)

header: magic(4) | version(1) | flags(1) | cipherId(1) | stepSeconds(4) | issuedAt(8)

The per-message key is derived via HKDF expansion from the master key, salt, and time metadata. The master key is derived once via PBKDF2-HMAC-SHA512 from the secret key and a fixed salt, then cached for subsequent operations.

Cipher IDs

ID Cipher
0x00 AES-256-GCM (default)
0x01 ChaCha20-Poly1305

Backward Compatibility

The decrypt path automatically detects the payload version and dispatches accordingly:

  • V5 - AEAD decrypt with HKDF-expanded key
  • V1-V4 - legacy 5-cipher-chain decrypt with PBKDF2-derived key

Legacy payloads can be rejected by setting AllowLegacyPayloads: false in DecryptOptions.

Installation

go get github.com/K9Crypt/k9crypt-go

Usage

Basic Encryption

package main

import (
    "fmt"
    "log"

    k9crypt "github.com/K9Crypt/k9crypt-go/src"
)

func main() {
    encryptor, err := k9crypt.New("VeryLongSecretKey!@#1234567890")
    if err != nil {
        log.Fatal(err)
    }

    encrypted, err := encryptor.Encrypt("Hello, World!")
    if err != nil {
        log.Fatal(err)
    }

    decrypted, err := encryptor.Decrypt(encrypted)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(decrypted)
}

Generated Key

encryptor, err := k9crypt.NewGenerated()
if err != nil {
    log.Fatal(err)
}

generatedKey := encryptor.GetGenerated()

Binary Payloads

data := []byte{0x00, 0xff, 0x10, 0x80}

encrypted, err := encryptor.EncryptBytes(data, nil)
if err != nil {
    log.Fatal(err)
}

decrypted, err := encryptor.DecryptBytes(encrypted, nil)
if err != nil {
    log.Fatal(err)
}

Time-Scoped Payloads And Freshness

issuedAt := int64(1700000000)
encrypted, err := encryptor.EncryptWithOptions("short-lived", &k9crypt.EncryptOptions{
    IssuedAtUnix:    &issuedAt,
    TimeStepSeconds: 300,
})
if err != nil {
    log.Fatal(err)
}

maxAge := int64(300)
now := int64(1700000100)
decrypted, err := encryptor.DecryptWithOptions(encrypted, &k9crypt.DecryptOptions{
    MaxAgeSeconds:           &maxAge,
    AllowedClockSkewSeconds: 30,
    NowUnixSeconds:          &now,
})
if err != nil {
    log.Fatal(err)
}

fmt.Println(decrypted)

Compression Override

level := 6
encrypted, err := encryptor.EncryptWithOptions("compressible payload", &k9crypt.EncryptOptions{
    CompressionLevel: &level,
})

Cipher Selection (V5)

chacha := byte(k9crypt.CipherChaCha20Poly1305)
encrypted, err := encryptor.EncryptWithOptions("ChaCha20 encrypted", &k9crypt.EncryptOptions{
    CipherId: &chacha,
})
if err != nil {
    log.Fatal(err)
}

// decrypt automatically detects the cipher from the payload header
decrypted, err := encryptor.Decrypt(encrypted)

For file and batch operations, pass CipherId through EncryptFileOptions or EncryptManyOptions:

chacha := byte(k9crypt.CipherChaCha20Poly1305)
encrypted, err := encryptor.EncryptFile(data, &k9crypt.EncryptFileOptions{
    CipherId: &chacha,
})

Buffered File Encryption

data := make([]byte, 1024*1024)

encrypted, err := encryptor.EncryptFile(data, &k9crypt.EncryptFileOptions{
    CompressionLevel: 0,
    CipherId:         nil, // nil = AES-256-GCM (default)
    OnProgress: func(p k9crypt.ProgressInfo) {
        fmt.Printf("%.0f%%\n", p.Percentage)
    },
})
if err != nil {
    log.Fatal(err)
}

decrypted, err := encryptor.DecryptFile(encrypted, nil)
if err != nil {
    log.Fatal(err)
}

fmt.Println(len(decrypted))

Batch Encryption

items := []string{"user1", "user2", "user3"}

encrypted, err := encryptor.EncryptMany(items, &k9crypt.EncryptManyOptions{
    CipherId:  nil, // nil = AES-256-GCM (default)
    Parallel:  true,
    BatchSize: 2,
})
if err != nil {
    log.Fatal(err)
}

decrypted, err := encryptor.DecryptMany(encrypted, &k9crypt.DecryptManyOptions{
    Parallel:    true,
    BatchSize:   2,
    SkipInvalid: false,
})
if err != nil {
    log.Fatal(err)
}

fmt.Println(decrypted)

Strict Compatibility Policy

allowLegacy := false
plaintext, err := encryptor.DecryptWithOptions(ciphertext, &k9crypt.DecryptOptions{
    AllowLegacyPayloads: &allowLegacy,
})

API Reference

Constructors

Function Description
New(secretKey string) (*K9Crypt, error) Creates an encryptor from a non-empty string secret.
NewGenerated() (*K9Crypt, error) Creates an encryptor with a 50-byte random secret.
NewWithKey(secretKey []byte) (*K9Crypt, error) Creates an encryptor from a cloned byte-slice secret; nil generates a key, empty slices are rejected.
NewWithOptions(secretKey string, compressionLevel int) (*K9Crypt, error) Creates a string-key encryptor with a default compression level.
NewWithKeyAndOptions(secretKey []byte, compressionLevel int) (*K9Crypt, error) Creates a byte-key encryptor with a default compression level.
NewGeneratedWithOptions(compressionLevel int) (*K9Crypt, error) Creates a generated-key encryptor with a default compression level.

Methods

Method Description
Encrypt(plaintext string) Encrypts a string with default options.
EncryptWithOptions(plaintext string, options *EncryptOptions) Encrypts a string with time/compression/cipher options.
EncryptBytes(plaintext []byte, options *EncryptOptions) Encrypts binary data and marks the payload as binary.
Decrypt(ciphertext string) Decrypts a string payload.
DecryptWithOptions(ciphertext string, options *DecryptOptions) Decrypts with freshness and compatibility policy checks.
DecryptBytes(ciphertext string, options *DecryptOptions) Decrypts and returns raw bytes.
EncryptFile(data []byte, options *EncryptFileOptions) Encrypts buffered file data up to 16 MB.
DecryptFile(ciphertext string, options *DecryptFileOptions) Decrypts buffered file data up to 16 MB.
EncryptMany(dataArray []string, options *EncryptManyOptions) Batch encrypts strings.
DecryptMany(ciphertextArray []string, options *DecryptManyOptions) Batch decrypts strings.
SetCompressionLevel(level int) Sets default compression level 0-9.
GetCompressionLevel() Returns current default compression level.
GetGenerated() Returns a copy of the generated secret, or nil for caller-provided secrets.

Constants

Constant Value Description
CipherAes256Gcm 0x00 AES-256-GCM cipher ID
CipherChaCha20Poly1305 0x01 ChaCha20-Poly1305 cipher ID
PayloadVersionV5 5 Current payload version
PayloadHeaderSizeV5 19 V5 header size in bytes
IvSizeV5 12 V5 IV/nonce size in bytes

Options

EncryptOptions

  • CompressionLevel *int - optional per-call compression level; 0 means raw mode.
  • TimeStepSeconds uint32 - optional time bucket size, default 300, maximum 86400.
  • IssuedAtUnix *int64 - optional authenticated issue time.
  • CipherId *byte - optional cipher selection; nil defaults to AES-256-GCM (0x00), use CipherChaCha20Poly1305 (0x01) for ChaCha20-Poly1305.

DecryptOptions

  • MaxAgeSeconds *int64 - optional freshness limit.
  • AllowedClockSkewSeconds int64 - optional clock skew allowance.
  • NowUnixSeconds *int64 - optional deterministic validation time.
  • AllowLegacyPayloads *bool - default true; set to false to reject pre-v5 payloads.

EncryptFileOptions / EncryptManyOptions also expose CipherId, compression, time metadata, progress, and parallel batch controls where applicable.

DecryptFileOptions / DecryptManyOptions also expose freshness, compatibility, progress, SkipInvalid, and parallel batch controls where applicable.

Security Design

V5 Encryption Flow

  1. Master key is derived once via PBKDF2-HMAC-SHA512 (600,000 iterations) from the secret key and a fixed salt, then cached
  2. Per-message: random 32-byte salt and 12-byte IV are generated
  3. Per-message key is derived via HMAC-SHA512 (HKDF expansion) from master key, salt, and time bucket metadata
  4. Plaintext is encrypted with the selected AEAD cipher (AES-256-GCM or ChaCha20-Poly1305) using the header as AAD
  5. Body is authenticated via HMAC-SHA512 with the per-message key
  6. Final payload is base64-encoded

V5 Decryption Flow

  1. Payload version is detected from the header
  2. V5 payloads: freshness validation, master key derivation, HKDF key expansion, MAC verification, AEAD decrypt
  3. Legacy V1-V4 payloads: policy check, hash/MAC verification, key derivation, 5-cipher-chain decrypt

Key Zeroization

All intermediate key material (per-message keys, derived keys) is zeroed after use via zeroBytes() to minimize sensitive data lifetime in memory.

License

This project is licensed under the MIT License.

About

A high-performance and secure data encryption library built to military standards.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages