crypto

AES-256 Encryption, SHA Hashing, and Base64 bindings for EZ Language

2 downloads owners: imabd645

Install

ez install crypto

Dependencies (1.0.1)

PackageRange
No dependencies.

Readme

crypto — Cryptography Library for EZ

Version: 1.0 Import: use "crypto" File: C:\ezlib\crypto\main.ez

Overview

crypto provides cryptographic primitives implemented in pure EZ using the language's native bitwise operators. It includes:

All operations are done entirely in EZ — no external DLLs or OS calls are needed.


Quick Start

use "crypto"

# Base64 encode
encoded = Crypto.base64Encode("Hello, World!")
out encoded   # → "SGVsbG8sIFdvcmxkIQ=="

# Base64 decode
decoded = Crypto.base64Decode("SGVsbG8sIFdvcmxkIQ==")
out decoded   # → "Hello, World!"

# RC4 encrypt
key = "mySecretKey"
cipherText = Crypto.rc4Encrypt(key, "Secret message")
out cipherText  # → Base64-encoded cipher

# RC4 decrypt
plainText = Crypto.rc4Decrypt(key, cipherText)
out plainText   # → "Secret message"

Model: Base64

The Base64 model provides static methods for encoding and decoding data using the standard Base64 alphabet (A-Z, a-z, 0-9, +, /).

Base64.encode(input)string

Encodes a string or byte array to Base64.

Parameters:

Returns: Base64-encoded string, padded with = as required.

Examples:

use "crypto"

# String input
out Base64.encode("Hello")      # → "SGVsbG8="
out Base64.encode("Hi")         # → "SGk="
out Base64.encode("A")          # → "QQ=="
out Base64.encode("")           # → ""

# Byte array input
out Base64.encode([72, 101, 108, 108, 111])  # → "SGVsbG8="

# Padding cases
out Base64.encode("Man")        # → "TWFu"    (no padding needed — 3 bytes)
out Base64.encode("Ma")         # → "TWE="    (1 pad char)
out Base64.encode("M")          # → "TQ=="    (2 pad chars)

Base64.decode(encoded)string

Decodes a Base64-encoded string back to a plain text string.

Parameters:

Returns: Decoded string, built by converting each byte back to a character via chr().

Examples:

use "crypto"

out Base64.decode("SGVsbG8=")       # → "Hello"
out Base64.decode("SGk=")           # → "Hi"
out Base64.decode("QQ==")           # → "A"
out Base64.decode("")               # → ""
out Base64.decode("SGVsbG8sIFdvcmxkIQ==")  # → "Hello, World!"
⚠️ Note: Base64.decode() assumes the encoded content represents printable ASCII text. For binary data (images, files, etc.), use Base64.decodeToBytes() instead.

Base64.decodeToBytes(encoded)array

Decodes a Base64 string to a raw byte array (array of integers 0–255).

Parameters:

Returns: Array of byte integers.

Examples:

use "crypto"

bytes = Base64.decodeToBytes("SGVsbG8=")
out bytes     # → [72, 101, 108, 108, 111]
out bytes[0]  # → 72 (ASCII 'H')

Use this when you need to work with binary data, BLOB content, or pipe decoded bytes into another operation.


Model: RC4

RC4 (Rivest Cipher 4) is a symmetric stream cipher. The same operation encrypts and decrypts — just apply with the same key.

⚠️ Security Warning: RC4 has known cryptographic weaknesses and should not be used for high-security applications. It is suitable for obfuscation, lightweight encoding, or educational purposes.

RC4.init(key)RC4 instance

Creates and initializes an RC4 cipher instance with the given key.

use "crypto"

cipher = RC4("my-secret-key-123")

RC4.processBytes(input)array

XORs the input with the RC4 keystream. Can be called with either a string or a byte array.

Parameters:

Returns: Array of byte integers (the cipher/plain text bytes).

Important: Each RC4 instance maintains state. After calling processBytes(), the internal i/j counters advance. To decrypt the same ciphertext, create a fresh RC4 instance with the same key.

Examples:

use "crypto"

key = "password"
plain = "Attack at dawn"

# Encrypt
encCipher = RC4(key)
encBytes = encCipher.processBytes(plain)
out encBytes   # → array of XOR'd bytes

# Decrypt (must use a NEW RC4 instance)
decCipher = RC4(key)
decBytes = decCipher.processBytes(encBytes)

result = ""
repeat i = 0 to len(decBytes) - 1 {
    result = result + chr(decBytes[i])
}
out result   # → "Attack at dawn"

Model: Crypto

The Crypto facade provides convenient static methods combining Base64 and RC4.

Crypto.base64Encode(text)string

Shorthand for Base64.encode(text).

use "crypto"

out Crypto.base64Encode("EZ Language!")  # → "RVogTGFuZ3VhZ2Uh"

Crypto.base64Decode(text)string

Shorthand for Base64.decode(text).

use "crypto"

out Crypto.base64Decode("RVogTGFuZ3VhZ2Uh")  # → "EZ Language!"

Crypto.rc4Encrypt(key, text)string

Encrypts plaintext with RC4 and returns a Base64-encoded cipher string (safe for storage and transmission).

Parameters:

Returns: Base64-encoded ciphertext string.

use "crypto"

cipher = Crypto.rc4Encrypt("SecretKey", "Hello World")
out cipher   # → Base64 string, e.g. "GvY3Sl/T8OaG"

Crypto.rc4Decrypt(key, base64Text)string

Decrypts an RC4-encrypted, Base64-encoded string.

Parameters:

Returns: Decrypted plaintext string.

use "crypto"

key = "SecretKey"
cipher = Crypto.rc4Encrypt(key, "My secret data")
plain = Crypto.rc4Decrypt(key, cipher)
out plain   # → "My secret data"

Edge Cases & Important Notes

Empty Inputs

use "crypto"

out Base64.encode("")        # → ""
out Base64.decode("")        # → ""
out Base64.decodeToBytes("") # → []

# RC4 with empty string
cipher = RC4("key")
out cipher.processBytes("")  # → []

# rc4Decrypt with empty cipher
out Crypto.rc4Decrypt("key", "")  # → ""

Key Length for RC4

RC4's KSA uses key[i % keyLen], so any key length from 1 to 256 bytes is valid. Longer keys (40+ chars) provide better security, though RC4 itself has fundamental vulnerabilities regardless.

RC4 State is Consumed

After calling processBytes(), the cipher state advances. Never reuse the same RC4 instance for a second message:

# WRONG — decryption will fail
cipher = RC4("key")
enc = cipher.processBytes("message1")
dec = cipher.processBytes(enc)    # ❌ Wrong! State is already advanced
out dec  # → garbage

# CORRECT — create fresh instances
enc = RC4("key").processBytes("message1")
dec = RC4("key").processBytes(enc)  # ✅ Fresh instance

Binary Data

If encoding binary data (non-text), use Base64.decodeToBytes() and work with byte arrays directly. Base64.decode() calls chr() on each byte, which only works correctly for ASCII range (0-127).

Non-ASCII Characters

Base64.encode() uses ord() on each character, which works correctly for ASCII. For multibyte Unicode strings, ord() returns the code point of the first byte only — behavior may be unexpected for non-ASCII input.

Invalid Base64 Input

If the input to Base64.decodeToBytes() or Base64.decode() contains characters not in the Base64 alphabet, indexOf() returns -1 which is treated as index 0. This means corrupted/invalid Base64 data will silently produce wrong output rather than an error.


Full Example: Config File Obfuscation

use "crypto"

APP_KEY = "MyAppSecretKey2024"

# Obfuscate sensitive config before saving
task saveConfig(data) {
    json = to_json(data)
    encrypted = Crypto.rc4Encrypt(APP_KEY, json)
    writeFile("config.dat", encrypted)
    out "Config saved (encrypted)."
}

# Load and decrypt config
task loadConfig() {
    raw = readFile("config.dat")
    json = Crypto.rc4Decrypt(APP_KEY, raw)
    give parse_json(json)
}

# Save config
config = {
    "db_host": "localhost",
    "db_pass": "supersecret",
    "api_key": "key-abc123"
}
saveConfig(config)

# Load it back
loaded = loadConfig()
out loaded["db_host"]  # → "localhost"
out loaded["api_key"]  # → "key-abc123"

Full Example: Token System

use "crypto"

SECRET = "server-signing-key"

# Create a token embedding user ID and expiry
task createToken(userId, expiryMs) {
    data = str(userId) + ":" + str(expiryMs)
    give Crypto.rc4Encrypt(SECRET, data)
}

# Validate and parse a token
task validateToken(token) {
    data = Crypto.rc4Decrypt(SECRET, token)
    parts = split(data, ":")
    
    when len(parts) != 2 {
        give nil   # Invalid format
    }
    
    userId = num(parts[0])
    expiry = num(parts[1])
    
    when clock() > expiry {
        give nil   # Token expired
    }
    
    give userId
}

# Create a token that expires in 1 hour
expiryTime = clock() + 3600000
token = createToken(42, expiryTime)
out "Token: " + token

# Validate
userId = validateToken(token)
when userId {
    out "Valid! User ID: " + str(userId)
} other {
    out "Invalid or expired token."
}

Full Example: Password Hashing Simulation

use "crypto"

# Simple (non-cryptographic) password storage simulation
task hashPassword(password, salt) {
    combined = salt + password
    give Crypto.base64Encode(Crypto.rc4Encrypt("static-server-key", combined))
}

task verifyPassword(password, salt, storedHash) {
    give hashPassword(password, salt) == storedHash
}

salt = "random-salt-abc"
stored = hashPassword("myPassword123", salt)
out "Stored: " + stored

out verifyPassword("myPassword123", salt, stored)  # → true
out verifyPassword("wrongPassword", salt, stored)   # → false

Algorithm Details

Base64 Encoding

RC4 Key Scheduling Algorithm (KSA)

Initialize S = [0, 1, 2, ..., 255]
j = 0
for i = 0 to 255:
    j = (j + S[i] + key[i % keyLen]) mod 256
    swap(S[i], S[j])

RC4 Pseudo-Random Generation Algorithm (PRGA)

i = 0, j = 0
for each byte of input:
    i = (i + 1) mod 256
    j = (j + S[i]) mod 256
    swap(S[i], S[j])
    K = S[(S[i] + S[j]) mod 256]
    output = input_byte XOR K

Documentation generated from C:\ezlib\crypto\main.ez — EZ Crypto Library

Versions

VersionSizeDownloadsPublished
1.0.1 10.7 KB 1 42 minutes ago
1.0.0 10.7 KB 1 1 hour ago

Integrity

sha256  7d4fb2236f7f7e7cfd98afea1f2cc1e610b12c78fc653be6583b4ef7e8ca3f3c