95 lines
3.1 KiB
Bash
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
|