...
This commit is contained in:
1
examples/crypt/.gitignore
vendored
Normal file
1
examples/crypt/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
crypt_example
|
||||||
103
examples/crypt/crypt_example.vsh
Executable file
103
examples/crypt/crypt_example.vsh
Executable file
@@ -0,0 +1,103 @@
|
|||||||
|
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals -no-skip-unused run
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.crypt.herocrypt
|
||||||
|
import time
|
||||||
|
|
||||||
|
// Initialize the HeroCrypt client
|
||||||
|
// Assumes herodb is running on localhost:6381
|
||||||
|
mut client := herocrypt.new_default()!
|
||||||
|
|
||||||
|
println('HeroCrypt client initialized')
|
||||||
|
|
||||||
|
// -- Stateless (Ephemeral) Workflow --
|
||||||
|
println('\n--- Stateless (Ephemeral) Workflow ---')
|
||||||
|
|
||||||
|
// 1. Generate ephemeral encryption keypair
|
||||||
|
println('Generating ephemeral encryption keypair...')
|
||||||
|
enc_keypair := client.gen_enc_keypair()!
|
||||||
|
recipient_pub := enc_keypair[0]
|
||||||
|
identity_sec := enc_keypair[1]
|
||||||
|
println(' Recipient Public Key: ${recipient_pub[..30]}...')
|
||||||
|
println(' Identity Secret Key: ${identity_sec[..30]}...')
|
||||||
|
|
||||||
|
// 2. Encrypt a message
|
||||||
|
message := 'Hello, Stateless World!'
|
||||||
|
println('\nEncrypting message: "${message}"')
|
||||||
|
ciphertext := client.encrypt(recipient_pub, message)!
|
||||||
|
println(' Ciphertext: ${ciphertext[..30]}...')
|
||||||
|
|
||||||
|
// 3. Decrypt the message
|
||||||
|
println('\nDecrypting ciphertext...')
|
||||||
|
decrypted_message := client.decrypt(identity_sec, ciphertext)!
|
||||||
|
println(' Decrypted Message: ${decrypted_message}')
|
||||||
|
assert decrypted_message == message
|
||||||
|
|
||||||
|
// 4. Generate ephemeral signing keypair
|
||||||
|
println('\nGenerating ephemeral signing keypair...')
|
||||||
|
sign_keypair := client.gen_sign_keypair()!
|
||||||
|
verify_pub_b64 := sign_keypair[0]
|
||||||
|
sign_sec_b64 := sign_keypair[1]
|
||||||
|
println(' Verify Public Key (b64): ${verify_pub_b64[..30]}...')
|
||||||
|
println(' Sign Secret Key (b64): ${sign_sec_b64[..30]}...')
|
||||||
|
|
||||||
|
// 5. Sign a message
|
||||||
|
sign_message := 'This message is signed.'
|
||||||
|
println('\nSigning message: "${sign_message}"')
|
||||||
|
signature := client.sign(sign_sec_b64, sign_message)!
|
||||||
|
println(' Signature: ${signature[..30]}...')
|
||||||
|
|
||||||
|
// 6. Verify the signature
|
||||||
|
println('\nVerifying signature...')
|
||||||
|
is_valid := client.verify(verify_pub_b64, sign_message, signature)!
|
||||||
|
println(' Signature is valid: ${is_valid}')
|
||||||
|
assert is_valid
|
||||||
|
|
||||||
|
// -- Key-Managed (Persistent, Named) Workflow --
|
||||||
|
println('\n--- Key-Managed (Persistent, Named) Workflow ---')
|
||||||
|
|
||||||
|
// 1. Generate and persist a named encryption keypair
|
||||||
|
enc_key_name := 'my_app_enc_key'
|
||||||
|
println('\nGenerating and persisting named encryption keypair: "${enc_key_name}"')
|
||||||
|
client.keygen(enc_key_name)!
|
||||||
|
|
||||||
|
// 2. Encrypt a message by name
|
||||||
|
persistent_message := 'Hello, Persistent World!'
|
||||||
|
println('Encrypting message by name: "${persistent_message}"')
|
||||||
|
persistent_ciphertext := client.encrypt_by_name(enc_key_name, persistent_message)!
|
||||||
|
println(' Ciphertext: ${persistent_ciphertext[..30]}...')
|
||||||
|
|
||||||
|
// 3. Decrypt the message by name
|
||||||
|
println('Decrypting ciphertext by name...')
|
||||||
|
decrypted_persistent_message := client.decrypt_by_name(enc_key_name, persistent_ciphertext)!
|
||||||
|
println(' Decrypted Message: ${decrypted_persistent_message}')
|
||||||
|
assert decrypted_persistent_message == persistent_message
|
||||||
|
|
||||||
|
// 4. Generate and persist a named signing keypair
|
||||||
|
sign_key_name := 'my_app_sign_key'
|
||||||
|
println('\nGenerating and persisting named signing keypair: "${sign_key_name}"')
|
||||||
|
client.sign_keygen(sign_key_name)!
|
||||||
|
|
||||||
|
// 5. Sign a message by name
|
||||||
|
persistent_sign_message := 'This persistent message is signed.'
|
||||||
|
println('Signing message by name: "${persistent_sign_message}"')
|
||||||
|
persistent_signature := client.sign_by_name(sign_key_name, persistent_sign_message)!
|
||||||
|
println(' Signature: ${persistent_signature[..30]}...')
|
||||||
|
|
||||||
|
// 6. Verify the signature by name
|
||||||
|
println('Verifying signature by name...')
|
||||||
|
is_persistent_valid := client.verify_by_name(sign_key_name, persistent_sign_message, persistent_signature)!
|
||||||
|
println(' Signature is valid: ${is_persistent_valid}')
|
||||||
|
assert is_persistent_valid
|
||||||
|
|
||||||
|
// // 7. List all stored keys
|
||||||
|
// println('\n--- Listing Stored Keys ---')
|
||||||
|
// keys := client.list_keys()!
|
||||||
|
// println('Stored keys: ${keys}')
|
||||||
|
|
||||||
|
// // -- Clean up created keys --
|
||||||
|
// println('\n--- Cleaning up ---')
|
||||||
|
// client.redis_client.del('age:enc:${enc_key_name}')!
|
||||||
|
// client.redis_client.del('age:sign:${sign_key_name}')!
|
||||||
|
// println('Cleaned up persistent keys.')
|
||||||
|
|
||||||
|
println('\nHeroCrypt example finished successfully!')
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
#!/bin/bash -e
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
# Help function
|
# Help function
|
||||||
print_help() {
|
print_help() {
|
||||||
|
|||||||
29
lib/core/redisclient/redisclient_cmd.v
Normal file
29
lib/core/redisclient/redisclient_cmd.v
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
module redisclient
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.data.resp
|
||||||
|
|
||||||
|
pub fn (mut r Redis) cmd_str(script string, args []string) !string {
|
||||||
|
mut cmds := []string{}
|
||||||
|
cmds << script
|
||||||
|
cmds << args
|
||||||
|
return r.send_expect_strnil(cmds)!
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut r Redis) cmd_list_str(script string, args []string) ![]string {
|
||||||
|
mut cmds := []string{}
|
||||||
|
cmds << script
|
||||||
|
cmds << args
|
||||||
|
response := r.send_expect_list(cmds)!
|
||||||
|
mut result := []string{}
|
||||||
|
for item in response {
|
||||||
|
result << resp.get_redis_value(item)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut r Redis) cmd_int(script string, args []string) !int {
|
||||||
|
mut cmds := []string{}
|
||||||
|
cmds << script
|
||||||
|
cmds << args
|
||||||
|
return r.send_expect_int(cmds)!
|
||||||
|
}
|
||||||
102
lib/crypt/herocrypt/herocrypt.v
Normal file
102
lib/crypt/herocrypt/herocrypt.v
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
module herocrypt
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.core.redisclient
|
||||||
|
|
||||||
|
// HeroCrypt provides a client for HeroDB's AGE cryptography features.
|
||||||
|
pub struct HeroCrypt {
|
||||||
|
pub mut:
|
||||||
|
redis_client &redisclient.Redis
|
||||||
|
}
|
||||||
|
|
||||||
|
// new returns a new HeroCrypt client
|
||||||
|
// url e.g. localhost:6381 (default)
|
||||||
|
// It pings the server to ensure a valid connection.
|
||||||
|
pub fn new(url_ string) !&HeroCrypt {
|
||||||
|
mut url := url_
|
||||||
|
if url == '' {
|
||||||
|
url = 'localhost:6381'
|
||||||
|
}
|
||||||
|
mut redis := redisclient.new(url)!
|
||||||
|
redis.ping()!
|
||||||
|
return &HeroCrypt{
|
||||||
|
redis_client: redis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new_default returns a new HeroCrypt client with the default URL.
|
||||||
|
pub fn new_default() !&HeroCrypt {
|
||||||
|
return new('')
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Stateless (Ephemeral) Methods --
|
||||||
|
|
||||||
|
// gen_enc_keypair generates an ephemeral encryption keypair.
|
||||||
|
// Returns: [recipient_public_key, identity_secret_key]
|
||||||
|
pub fn (mut self HeroCrypt) gen_enc_keypair() ![]string {
|
||||||
|
return self.redis_client.cmd_list_str('AGE', ['GENENC'])
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt encrypts a message with a recipient public key.
|
||||||
|
pub fn (mut self HeroCrypt) encrypt(recipient_public_key string, message string) !string {
|
||||||
|
return self.redis_client.cmd_str('AGE', ['ENCRYPT', recipient_public_key, message])
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt decrypts a ciphertext with an identity secret key.
|
||||||
|
pub fn (mut self HeroCrypt) decrypt(identity_secret_key string, ciphertext_b64 string) !string {
|
||||||
|
return self.redis_client.cmd_str('AGE', ['DECRYPT', identity_secret_key, ciphertext_b64])
|
||||||
|
}
|
||||||
|
|
||||||
|
// gen_sign_keypair generates an ephemeral signing keypair.
|
||||||
|
// Returns: [verify_public_key_b64, sign_secret_key_b64]
|
||||||
|
pub fn (mut self HeroCrypt) gen_sign_keypair() ![]string {
|
||||||
|
return self.redis_client.cmd_list_str('AGE', ['GENSIGN'])
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign signs a message with a signing secret key.
|
||||||
|
pub fn (mut self HeroCrypt) sign(sign_secret_key_b64 string, message string) !string {
|
||||||
|
return self.redis_client.cmd_str('AGE', ['SIGN', sign_secret_key_b64, message])
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify verifies a signature with a public verification key.
|
||||||
|
pub fn (mut self HeroCrypt) verify(verify_public_key_b64 string, message string, signature_b64 string) !bool {
|
||||||
|
res := self.redis_client.cmd_str('AGE', ['VERIFY', verify_public_key_b64, message, signature_b64])!
|
||||||
|
return res == '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Key-Managed (Persistent, Named) Methods --
|
||||||
|
|
||||||
|
// keygen generates and persists a named encryption keypair.
|
||||||
|
pub fn (mut self HeroCrypt) keygen(name string) ![]string {
|
||||||
|
return self.redis_client.cmd_list_str('AGE', ['KEYGEN', name])
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt_by_name encrypts a message using a named key.
|
||||||
|
pub fn (mut self HeroCrypt) encrypt_by_name(name string, message string) !string {
|
||||||
|
return self.redis_client.cmd_str('AGE', ['ENCRYPTNAME', name, message])
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt_by_name decrypts a ciphertext using a named key.
|
||||||
|
pub fn (mut self HeroCrypt) decrypt_by_name(name string, ciphertext_b64 string) !string {
|
||||||
|
return self.redis_client.cmd_str('AGE', ['DECRYPTNAME', name, ciphertext_b64])
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign_keygen generates and persists a named signing keypair.
|
||||||
|
pub fn (mut self HeroCrypt) sign_keygen(name string) ![]string {
|
||||||
|
return self.redis_client.cmd_list_str('AGE', ['SIGNKEYGEN', name])
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign_by_name signs a message using a named signing key.
|
||||||
|
pub fn (mut self HeroCrypt) sign_by_name(name string, message string) !string {
|
||||||
|
return self.redis_client.cmd_str('AGE', ['SIGNNAME', name, message])
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_by_name verifies a signature with a named verification key.
|
||||||
|
pub fn (mut self HeroCrypt) verify_by_name(name string, message string, signature_b64 string) !bool {
|
||||||
|
res := self.redis_client.cmd_str('AGE', ['VERIFYNAME', name, message, signature_b64])!
|
||||||
|
return res == '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
// // list_keys lists all stored AGE keys.
|
||||||
|
// pub fn (mut self HeroCrypt) list_keys() ![]string {
|
||||||
|
// return self.redis_client.cmd_list_str('AGE', ['LIST'])
|
||||||
|
// }
|
||||||
116
lib/crypt/herocrypt/readme.md
Normal file
116
lib/crypt/herocrypt/readme.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# HeroCrypt: Effortless Cryptography with HeroDB
|
||||||
|
|
||||||
|
HeroCrypt is a library that provides a simple and secure way to handle encryption and digital signatures by leveraging the power of [HeroDB](https://git.ourworld.tf/herocode/herodb). It abstracts the underlying complexity of cryptographic operations, allowing you to secure your application's data with minimal effort.
|
||||||
|
|
||||||
|
## What is HeroDB?
|
||||||
|
|
||||||
|
HeroDB is a high-performance, Redis-compatible database that offers built-in support for advanced cryptographic operations using the [AGE encryption format](https://age-encryption.org/). This integration makes it an ideal backend for applications requiring robust, end-to-end security.
|
||||||
|
|
||||||
|
## Core Features of HeroCrypt
|
||||||
|
|
||||||
|
- **Encryption & Decryption**: Securely encrypt and decrypt data.
|
||||||
|
- **Digital Signatures**: Sign and verify messages to ensure their integrity and authenticity.
|
||||||
|
- **Flexible Key Management**: Choose between two modes for managing your cryptographic keys:
|
||||||
|
1. **Key-Managed (Server-Side)**: Let HeroDB manage your keys. Keys are stored securely within the database and are referenced by a name. This is the recommended approach for simplicity and centralized key management.
|
||||||
|
2. **Stateless (Client-Side)**: Manage your own keys on the client side. You pass the key material with every cryptographic operation. This mode is for advanced users who require full control over their keys.
|
||||||
|
|
||||||
|
|
||||||
|
## To start a db see
|
||||||
|
|
||||||
|
https://git.ourworld.tf/herocode/herodb
|
||||||
|
|
||||||
|
to do:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hero git pull https://git.ourworld.tf/herocode/herodb
|
||||||
|
~/code/git.ourworld.tf/herocode/herodb/run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key-Managed Mode (Recommended)
|
||||||
|
|
||||||
|
In this mode, HeroDB generates and stores the keypairs for you. You only need to provide a name for your key.
|
||||||
|
|
||||||
|
### Encryption
|
||||||
|
|
||||||
|
```v
|
||||||
|
import freeflowuniverse.herolib.crypt.herocrypt
|
||||||
|
|
||||||
|
mut client := herocrypt.new_default()!
|
||||||
|
|
||||||
|
// Generate and persist a named encryption keypair
|
||||||
|
client.keygen('my_app_key')!
|
||||||
|
|
||||||
|
// Encrypt a message
|
||||||
|
message := 'This is a secret message.'
|
||||||
|
ciphertext := client.encrypt_by_name('my_app_key', message)!
|
||||||
|
|
||||||
|
// Decrypt the message
|
||||||
|
decrypted_message := client.decrypt_by_name('my_app_key', ciphertext)!
|
||||||
|
assert decrypted_message == message
|
||||||
|
```
|
||||||
|
|
||||||
|
### Signing
|
||||||
|
|
||||||
|
```v
|
||||||
|
import freeflowuniverse.herolib.crypt.herocrypt
|
||||||
|
|
||||||
|
mut client := herocrypt.new_default()!
|
||||||
|
|
||||||
|
// Generate and persist a named signing keypair
|
||||||
|
client.sign_keygen('my_signer_key')!
|
||||||
|
|
||||||
|
// Sign a message
|
||||||
|
message := 'This message needs to be signed.'
|
||||||
|
signature := client.sign_by_name('my_signer_key', message)!
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
is_valid := client.verify_by_name('my_signer_key', message, signature)!
|
||||||
|
assert is_valid
|
||||||
|
```
|
||||||
|
|
||||||
|
## Stateless Mode (Advanced)
|
||||||
|
|
||||||
|
In this mode, you are responsible for generating and managing your own keys.
|
||||||
|
|
||||||
|
### Encryption
|
||||||
|
|
||||||
|
```v
|
||||||
|
import freeflowuniverse.herolib.crypt.herocrypt
|
||||||
|
|
||||||
|
mut client := herocrypt.new_default()!
|
||||||
|
|
||||||
|
// Generate an ephemeral encryption keypair
|
||||||
|
keypair := client.gen_enc_keypair()!
|
||||||
|
recipient_pub := keypair[0]
|
||||||
|
identity_sec := keypair[1]
|
||||||
|
|
||||||
|
// Encrypt a message
|
||||||
|
message := 'This is a secret message.'
|
||||||
|
ciphertext := client.encrypt(recipient_pub, message)!
|
||||||
|
|
||||||
|
// Decrypt the message
|
||||||
|
decrypted_message := client.decrypt(identity_sec, ciphertext)!
|
||||||
|
assert decrypted_message == message
|
||||||
|
```
|
||||||
|
|
||||||
|
### Signing
|
||||||
|
|
||||||
|
```v
|
||||||
|
import freeflowuniverse.herolib.crypt.herocrypt
|
||||||
|
|
||||||
|
mut client := herocrypt.new_default()!
|
||||||
|
|
||||||
|
// Generate an ephemeral signing keypair
|
||||||
|
keypair := client.gen_sign_keypair()!
|
||||||
|
verify_pub_b64 := keypair[0]
|
||||||
|
sign_sec_b64 := keypair[1]
|
||||||
|
|
||||||
|
// Sign a message
|
||||||
|
message := 'This message needs to be signed.'
|
||||||
|
signature := client.sign(sign_sec_b64, message)!
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
is_valid := client.verify(verify_pub_b64, message, signature)!
|
||||||
|
assert is_valid
|
||||||
|
|
||||||
|
```
|
||||||
84
lib/crypt/herocrypt/specs.md
Normal file
84
lib/crypt/herocrypt/specs.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# HeroCrypt Technical Specifications
|
||||||
|
|
||||||
|
This document provides the low-level technical details for the HeroCrypt library, including the underlying Redis commands used to interact with HeroDB's AGE cryptography features.
|
||||||
|
|
||||||
|
## Communication Protocol
|
||||||
|
|
||||||
|
HeroCrypt communicates with HeroDB using the standard Redis protocol. All commands are sent as RESP (Redis Serialization Protocol) arrays.
|
||||||
|
|
||||||
|
## Stateless (Ephemeral) AGE Operations
|
||||||
|
|
||||||
|
These commands are used when the client manages its own keys.
|
||||||
|
|
||||||
|
### Encryption
|
||||||
|
|
||||||
|
- **`AGE GENENC`**: Generates an ephemeral encryption keypair.
|
||||||
|
- **Returns**: An array containing the recipient (public key) and the identity (secret key).
|
||||||
|
|
||||||
|
- **`AGE ENCRYPT <recipient> <message>`**: Encrypts a message using the recipient's public key.
|
||||||
|
- **`<recipient>`**: The public key (`age1...`).
|
||||||
|
- **`<message>`**: The plaintext message to encrypt.
|
||||||
|
- **Returns**: A base64-encoded ciphertext.
|
||||||
|
|
||||||
|
- **`AGE DECRYPT <identity> <ciphertext>`**: Decrypts a ciphertext using the identity (secret key).
|
||||||
|
- **`<identity>`**: The secret key (`AGE-SECRET-KEY-1...`).
|
||||||
|
- **`<ciphertext>`**: The base64-encoded ciphertext.
|
||||||
|
- **Returns**: The decrypted plaintext message.
|
||||||
|
|
||||||
|
### Signing
|
||||||
|
|
||||||
|
- **`AGE GENSIGN`**: Generates an ephemeral signing keypair.
|
||||||
|
- **Returns**: An array containing the public verification key (base64) and the secret signing key (base64).
|
||||||
|
|
||||||
|
- **`AGE SIGN <sign_secret_b64> <message>`**: Signs a message with the secret key.
|
||||||
|
- **`<sign_secret_b64>`**: The base64-encoded secret signing key.
|
||||||
|
- **`<message>`**: The message to sign.
|
||||||
|
- **Returns**: A base64-encoded signature.
|
||||||
|
|
||||||
|
- **`AGE VERIFY <verify_pub_b64> <message> <signature_b64>`**: Verifies a signature.
|
||||||
|
- **`<verify_pub_b64>`**: The base64-encoded public verification key.
|
||||||
|
- **`<message>`**: The original message.
|
||||||
|
- **`<signature_b64>`**: The base64-encoded signature.
|
||||||
|
- **Returns**: `1` if the signature is valid, `0` otherwise.
|
||||||
|
|
||||||
|
## Key-Managed (Persistent, Named) AGE Operations
|
||||||
|
|
||||||
|
These commands are used when HeroDB manages the keys.
|
||||||
|
|
||||||
|
### Encryption
|
||||||
|
|
||||||
|
- **`AGE KEYGEN <name>`**: Generates and persists a named encryption keypair.
|
||||||
|
- **`<name>`**: A unique name for the key.
|
||||||
|
- **Returns**: An array containing the recipient and identity (for initial export, if needed).
|
||||||
|
|
||||||
|
- **`AGE ENCRYPTNAME <name> <message>`**: Encrypts a message using a named key.
|
||||||
|
- **`<name>`**: The name of the stored key.
|
||||||
|
- **`<message>`**: The plaintext message.
|
||||||
|
- **Returns**: A base64-encoded ciphertext.
|
||||||
|
|
||||||
|
- **`AGE DECRYPTNAME <name> <ciphertext>`**: Decrypts a ciphertext using a named key.
|
||||||
|
- **`<name>`**: The name of the stored key.
|
||||||
|
- **`<ciphertext>`**: The base64-encoded ciphertext.
|
||||||
|
- **Returns**: The decrypted plaintext message.
|
||||||
|
|
||||||
|
### Signing
|
||||||
|
|
||||||
|
- **`AGE SIGNKEYGEN <name>`**: Generates and persists a named signing keypair.
|
||||||
|
- **`<name>`**: A unique name for the key.
|
||||||
|
- **Returns**: An array containing the public and secret keys (for initial export).
|
||||||
|
|
||||||
|
- **`AGE SIGNNAME <name> <message>`**: Signs a message using a named key.
|
||||||
|
- **`<name>`**: The name of the stored key.
|
||||||
|
- **`<message>`**: The message to sign.
|
||||||
|
- **Returns**: A base64-encoded signature.
|
||||||
|
|
||||||
|
- **`AGE VERIFYNAME <name> <message> <signature_b64>`**: Verifies a signature using a named key.
|
||||||
|
- **`<name>`**: The name of the stored key.
|
||||||
|
- **`<message>`**: The original message.
|
||||||
|
- **`<signature_b64>`**: The base64-encoded signature.
|
||||||
|
- **Returns**: `1` if the signature is valid, `0` otherwise.
|
||||||
|
|
||||||
|
### Key Listing
|
||||||
|
|
||||||
|
- **`AGE LIST`**: Lists all stored AGE keys.
|
||||||
|
- **Returns**: An array of key names.
|
||||||
Reference in New Issue
Block a user