Skip to content

Native (Crypto)

Access native Rust functions for encryption.

Uses AES-256-GCM for secure encryption.

Methods

isAvailable()

Check if native module is loaded:

javascript
if (gemshell.native.isAvailable()) {
  // Native functions available
}

getVersion()

Get native module version:

javascript
const version = gemshell.native.getVersion();
// "0.6.0"

encrypt(key, text)

Encrypt a string:

javascript
const encrypted = gemshell.native.encrypt('my-secret-key', 'Hello World');
// Returns Base64 encoded ciphertext

decrypt(key, ciphertext)

Decrypt a string:

javascript
const decrypted = gemshell.native.decrypt('my-secret-key', encrypted);
// "Hello World"

encryptBytes(key, buffer)

Encrypt a Buffer:

javascript
const data = Buffer.from([1, 2, 3, 4, 5]);
const encrypted = gemshell.native.encryptBytes('my-key', data);

decryptBytes(key, buffer)

Decrypt a Buffer:

javascript
const decrypted = gemshell.native.decryptBytes('my-key', encrypted);

Key Requirements

  • Keys can be any string
  • Internally hashed to 256-bit key
  • Use strong, unique keys for security

Example: Encrypt Save Data

javascript
module.exports = {
  name: 'Save Encryptor',
  version: '1.0.0',
  
  settings: [
    { id: 'encryptionKey', type: 'text', label: 'Encryption Key', default: '' }
  ],
  
  async onModifyAssets(context, settings) {
    if (!settings.encryptionKey) {
      gemshell.warn('No encryption key set, skipping');
      return;
    }
    
    // Find save data files
    const saveFiles = gemshell.glob('data/*.json');
    
    for (const file of saveFiles) {
      const content = gemshell.fs.read(file);
      const encrypted = gemshell.native.encrypt(settings.encryptionKey, content);
      
      // Write encrypted version
      gemshell.fs.write(file + '.enc', encrypted);
      gemshell.fs.remove(file);
      
      gemshell.log(`Encrypted: ${file}`);
    }
  }
};

Example: Protect API Keys

javascript
module.exports = {
  name: 'API Key Protector',
  version: '1.0.0',
  
  settings: [
    { id: 'masterKey', type: 'text', label: 'Master Key' }
  ],
  
  async onModifyAssets(context, settings) {
    if (!settings.masterKey) return;
    
    // Read config with sensitive data
    if (!gemshell.fs.exists('config.json')) return;
    
    const config = gemshell.fs.readJson('config.json');
    
    // Encrypt sensitive fields
    if (config.apiKey) {
      config.apiKey = gemshell.native.encrypt(settings.masterKey, config.apiKey);
      config.apiKeyEncrypted = true;
    }
    
    if (config.secret) {
      config.secret = gemshell.native.encrypt(settings.masterKey, config.secret);
      config.secretEncrypted = true;
    }
    
    gemshell.fs.writeJson('config.json', config);
    gemshell.log('Sensitive data encrypted');
  }
};

Security Notes

  1. Never hardcode keys - Use settings or environment variables
  2. Use unique keys per game - Don't reuse keys across projects
  3. AES-256-GCM provides authenticated encryption
  4. Keys are hashed - Any string works, but longer is better

Decryption in Game

To decrypt at runtime in your game, you'll need to implement decryption in JavaScript or use a library:

javascript
// In your game code (not plugin)
// You'll need a JS crypto library like crypto-js

import CryptoJS from 'crypto-js';

function decrypt(key, ciphertext) {
  // Note: This is a simplified example
  // The actual format depends on your encryption implementation
  const bytes = CryptoJS.AES.decrypt(ciphertext, key);
  return bytes.toString(CryptoJS.enc.Utf8);
}

Or use the GemCore API if available:

javascript
// Using GemCore native crypto (if exposed)
const decrypted = await gemcore.crypto.decrypt(key, encrypted);