{"service": "s3-proxy", "description": "Authenticated proxy access to S3 operations with HMAC-SHA256 authentication", "instructions_source": {"note": "This documentation is loaded from s3://jerimiahbaldwin-store/instructions.json", "update_instructions": "Authenticate and use put_object operation to update this file without redeploying code"}, "authentication": {"type": "HMAC-SHA256", "method": "PBKDF2 key derivation with SHA256", "required_headers": ["X-Key-Id", "X-Timestamp", "X-Nonce", "X-Signature"], "signature_process": {"step_1": "Hash request body with SHA256 and get hexdigest (empty body = sha256 of empty bytes)", "step_2": "Build canonical message with newlines (not pipes): METHOD\\nPATH\\nQUERY\\nBODY_SHA256\\nTIMESTAMP\\nNONCE", "step_3": "Derive key using PBKDF2-HMAC-SHA256(passphrase, key_id as salt, iterations)", "step_4": "Sign canonical message with HMAC-SHA256 using derived key", "step_5": "Encode signature as hexadecimal (NOT base64)"}, "important_notes": ["Body must be SHA256-hashed first (use .hexdigest(), not the raw hash)", "Canonical message uses newline separators (\\n), not pipes or other delimiters", "Signature must be hex-encoded, not base64", "Nonce should be a UUID string (uuid.uuid4()), not random bytes", "PBKDF2 must use SHA256 (hashlib.pbkdf2_hmac('sha256', ...))", "Query string must be canonicalized: sorted keys, URL-encoded, joined with &", "Empty query string = empty string, not null or omitted"], "example_canonical_message": "POST\\n/\\n\\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\\n1714348800\\na1b2c3d4-e5f6-7890-abcd-ef1234567890", "key_id": "s3-proxy-key", "max_timestamp_skew_seconds": 300, "pbkdf2_iterations": 200000}, "quick_start_examples": {"note": "Using example passphrase 'Super Secret Passphrase!' for demonstration", "python": "import hashlib,hmac,json,time,uuid;ts=str(int(time.time()));n=str(uuid.uuid4());body=json.dumps({'operation':'list_objects_v2','params':{'Bucket':'jerimiahbaldwin-store'}});h=hashlib.sha256(body.encode()).hexdigest();m=f\"POST\\n/\\n\\n{h}\\n{ts}\\n{n}\";k=hashlib.pbkdf2_hmac('sha256',b'Super Secret Passphrase!',b's3-proxy-key',200000);sig=hmac.new(k,m.encode(),hashlib.sha256).hexdigest();print(f\"X-Key-Id: s3-proxy-key\\nX-Timestamp: {ts}\\nX-Nonce: {n}\\nX-Signature: {sig}\")", "javascript": "const crypto=require('crypto');const ts=Math.floor(Date.now()/1000).toString();const n=crypto.randomUUID();const body=JSON.stringify({operation:'list_objects_v2',params:{Bucket:'jerimiahbaldwin-store'}});const h=crypto.createHash('sha256').update(body).digest('hex');const m=`POST\\n/\\n\\n${h}\\n${ts}\\n${n}`;const k=crypto.pbkdf2Sync('Super Secret Passphrase!','s3-proxy-key',200000,32,'sha256');const sig=crypto.createHmac('sha256',k).update(m).digest('hex');console.log(`X-Key-Id: s3-proxy-key\\nX-Timestamp: ${ts}\\nX-Nonce: ${n}\\nX-Signature: ${sig}`);", "powershell": "$ts=[int](Get-Date -UFormat %s);$n=[guid]::NewGuid();$body='{\"operation\":\"list_objects_v2\",\"params\":{\"Bucket\":\"jerimiahbaldwin-store\"}}';$h=([System.Security.Cryptography.SHA256]::Create().ComputeHash([Text.Encoding]::UTF8.GetBytes($body))|ForEach-Object{$_.ToString('x2')})-join'';$m=\"POST`n/`n`n$h`n$ts`n$n\";$k=(New-Object Security.Cryptography.Rfc2898DeriveBytes('Super Secret Passphrase!',[Text.Encoding]::UTF8.GetBytes('s3-proxy-key'),200000,'SHA256')).GetBytes(32);$sig=([Security.Cryptography.HMACSHA256]::new($k).ComputeHash([Text.Encoding]::UTF8.GetBytes($m))|ForEach-Object{$_.ToString('x2')})-join'';Write-Host \"X-Key-Id: s3-proxy-key`nX-Timestamp: $ts`nX-Nonce: $n`nX-Signature: $sig\"", "bash": "ts=$(date +%s);n=$(uuidgen);body='{\"operation\":\"list_objects_v2\",\"params\":{\"Bucket\":\"jerimiahbaldwin-store\"}}';h=$(echo -n \"$body\"|openssl dgst -sha256 -hex|cut -d' ' -f2);m=\"POST\\n/\\n\\n$h\\n$ts\\n$n\";k=$(echo -n 'Super Secret Passphrase!'|openssl enc -pbkdf2 -pass stdin -S $(echo -n 's3-proxy-key'|xxd -p) -iter 200000 -md sha256 -p 2>&1|grep '^key='|cut -d= -f2);sig=$(echo -n \"$m\"|openssl dgst -sha256 -mac HMAC -macopt hexkey:$k|cut -d' ' -f2);echo \"X-Key-Id: s3-proxy-key\nX-Timestamp: $ts\nX-Nonce: $n\nX-Signature: $sig\""}, "usage": {"method": "POST", "endpoint": "/", "body_format": {"operation": "operation_name", "params": {"Bucket": "bucket-name", "Key": "object-key"}}}, "endpoints": {"/health": "Health check (no auth required)", "/": "Info page (shows operations when authenticated, instructions when not)", "POST /*": "S3 operations (auth required)"}, "authenticated": false, "bucket": "jerimiahbaldwin-store", "root_folders": ["images/", "secrets/", "test/"]}