Files
n_signer/tools/otp_roundtrip_test.sh

95 lines
3.1 KiB
Bash

#!/bin/bash
# otp_roundtrip_test.sh — end-to-end test of otp_encrypt / otp_decrypt verbs.
#
# Sends framed JSON-RPC requests to nsigner --listen stdio and checks the
# round-trip: plaintext -> otp_encrypt -> otp_decrypt -> recovered plaintext.
#
# Usage: ./tools/otp_roundtrip_test.sh
set -euo pipefail
NSIGNER="./build/nsigner"
PAD_DIR="/media/user/Music/pads"
PAD_SPEC="333e9902db839d9d"
MNEMONIC_FILE=".test_mnemonic"
if [ ! -x "$NSIGNER" ]; then
echo "ERROR: $NSIGNER not found. Run 'make dev' first."
exit 1
fi
# Helper: send a framed JSON-RPC request to nsigner stdio and print the response.
# Framing: 4-byte big-endian length prefix + JSON payload.
send_request() {
local json="$1"
local len=${#json}
# 4-byte big-endian length
printf '\\x%02x\\x%02x\\x%02x\\x%02x' \
$(( (len >> 24) & 0xff )) $(( (len >> 16) & 0xff )) \
$(( (len >> 8) & 0xff )) $(( len & 0xff ))
printf '%s' "$json"
}
# Build the plaintext base64. "Hello, OTP world!" -> base64
PLAINTEXT_B64=$(printf 'Hello, OTP world!' | base64)
echo "Plaintext base64: $PLAINTEXT_B64"
# Build the encrypt request
ENCRYPT_REQ=$(cat <<EOF
{"id":"1","method":"otp_encrypt","params":["$PLAINTEXT_B64",{"encoding":"ascii"}]}
EOF
)
echo "=== Sending otp_encrypt ==="
RESPONSE=$( (printf '\\x00\\x00\\x00\\x%02x' ${#ENCRYPT_REQ}; printf '%s' "$ENCRYPT_REQ") | \
(exec 3<"$MNEMONIC_FILE"; "$NSIGNER" --listen stdio --mnemonic-fd 3 \
--otp-pad-dir "$PAD_DIR" --otp-pad "$PAD_SPEC" --otp-allow-blkback --allow-all) 2>/dev/null \
| tail -1 )
echo "Encrypt response: $RESPONSE"
# Extract the ciphertext field (rough parse — look for "ciphertext":"...")
CIPHERTEXT=$(echo "$RESPONSE" | sed -n 's/.*"ciphertext":"\([^"]*\)".*/\1/p')
if [ -z "$CIPHERTEXT" ]; then
echo "ERROR: no ciphertext in response"
exit 1
fi
echo "Ciphertext (first 80 chars): ${CIPHERTEXT:0:80}..."
# Build the decrypt request — the ciphertext is the ASCII armor (with newlines
# escaped as \n in JSON). We need to properly JSON-escape it.
# Use python to do the JSON encoding safely.
DECRYPT_REQ=$(python3 -c "
import json, sys
ct = sys.argv[1]
print(json.dumps({'id':'2','method':'otp_decrypt','params':[ct,{'encoding':'ascii'}]}))
" "$CIPHERTEXT")
echo "=== Sending otp_decrypt ==="
RESPONSE2=$( (printf '\\x00\\x00\\x00\\x%02x' ${#DECRYPT_REQ}; printf '%s' "$DECRYPT_REQ") | \
(exec 3<"$MNEMONIC_FILE"; "$NSIGNER" --listen stdio --mnemonic-fd 3 \
--otp-pad-dir "$PAD_DIR" --otp-pad "$PAD_SPEC" --otp-allow-blkback --allow-all) 2>/dev/null \
| tail -1 )
echo "Decrypt response: $RESPONSE2"
# Extract and decode the recovered plaintext
RECOVERED_B64=$(echo "$RESPONSE2" | sed -n 's/.*"plaintext":"\([^"]*\)".*/\1/p')
if [ -z "$RECOVERED_B64" ]; then
echo "ERROR: no plaintext in decrypt response"
exit 1
fi
RECOVERED=$(echo "$RECOVERED_B64" | base64 -d 2>/dev/null)
echo "Recovered plaintext: $RECOVERED"
if [ "$RECOVERED" = "Hello, OTP world!" ]; then
echo ""
echo "=== ROUND-TRIP SUCCESS ==="
exit 0
else
echo ""
echo "=== ROUND-TRIP FAILED ==="
echo "Expected: Hello, OTP world!"
echo "Got: $RECOVERED"
exit 1
fi