// platform_crypto — Arcrun 平台內部 crypto primitive // // Actions: // generate_api_key — HMAC-SHA256(email, ENCRYPTION_KEY) → ak_{hex[:32]} // encrypt — AES-GCM(plaintext, ENCRYPTION_KEY) → {encrypted, iv}(base64) // random_token — crypto random bytes → hex string // // ENCRYPTION_KEY 由 host 持有,永不進入 WASM。 // // Host imports: // u6u.crypto_hmac_sha256 — HMAC-SHA256(data, key=ENCRYPTION_KEY) → raw bytes // u6u.crypto_aes_encrypt — AES-GCM(plaintext, key=ENCRYPTION_KEY) → encrypted_b64 + iv_b64 // u6u.crypto_random_bytes — crypto-random bytes → hex string // //go:build tinygo package main import ( "encoding/json" "io" "os" "strings" "unsafe" ) // ── host function 宣告 ─────────────────────────────────────────────────────── // crypto_hmac_sha256(dataPtr, dataLen, outPtr, outLenPtr) → 0 成功 // key = host 的 ENCRYPTION_KEY,output = raw bytes(hex encode 由 WASM 做) // //go:wasmimport u6u crypto_hmac_sha256 func hostCryptoHmacSha256( dataPtr uintptr, dataLen uint32, outPtr uintptr, outLenPtr uintptr, ) uint32 // crypto_aes_encrypt(plaintextPtr, plaintextLen, outEncPtr, outEncLenPtr, outIvPtr, outIvLenPtr) → 0 成功 // output: encrypted(base64)放 outEnc,iv(base64)放 outIv // //go:wasmimport u6u crypto_aes_encrypt func hostCryptoAesEncrypt( plaintextPtr uintptr, plaintextLen uint32, outEncPtr uintptr, outEncLenPtr uintptr, outIvPtr uintptr, outIvLenPtr uintptr, ) uint32 // crypto_random_bytes(numBytes, outPtr, outLenPtr) → 0 成功 // output: hex string // //go:wasmimport u6u crypto_random_bytes func hostCryptoRandomBytes( numBytes uint32, outPtr uintptr, outLenPtr uintptr, ) uint32 // ── 型別 ───────────────────────────────────────────────────────────────────── type Input struct { Action string `json:"action"` Email string `json:"email,omitempty"` Plaintext string `json:"plaintext,omitempty"` Bytes int `json:"bytes,omitempty"` } // ── main ───────────────────────────────────────────────────────────────────── func main() { raw, err := io.ReadAll(os.Stdin) if err != nil { writeError("failed to read stdin: " + err.Error()) return } var input Input if err := json.Unmarshal(raw, &input); err != nil { writeError("invalid input JSON: " + err.Error()) return } switch input.Action { case "generate_api_key": if input.Email == "" { writeError("email 必填") return } sig, ok := hmacSha256([]byte(input.Email)) if !ok { writeError("HMAC-SHA256 失敗") return } apiKey := "ak_" + hex(sig)[:32] out, _ := json.Marshal(map[string]interface{}{ "success": true, "api_key": apiKey, }) os.Stdout.Write(out) case "encrypt": if input.Plaintext == "" { writeError("plaintext 必填") return } encB64, ivB64, ok := aesEncrypt([]byte(input.Plaintext)) if !ok { writeError("AES-GCM 加密失敗") return } out, _ := json.Marshal(map[string]interface{}{ "success": true, "encrypted": encB64, "iv": ivB64, }) os.Stdout.Write(out) case "random_token": n := input.Bytes if n <= 0 { n = 32 } token, ok := randomBytes(uint32(n)) if !ok { writeError("random bytes 失敗") return } out, _ := json.Marshal(map[string]interface{}{ "success": true, "token": token, }) os.Stdout.Write(out) default: writeError("不支援的 action: " + input.Action) } } // ── helpers ─────────────────────────────────────────────────────────────────── func writeError(msg string) { out, _ := json.Marshal(map[string]interface{}{ "success": false, "error": msg, }) os.Stdout.Write(out) } func hmacSha256(data []byte) ([]byte, bool) { if len(data) == 0 { return nil, false } outBuf := make([]byte, 64) // SHA-256 = 32 bytes raw var outLen uint32 status := hostCryptoHmacSha256( uintptr(unsafe.Pointer(&data[0])), uint32(len(data)), uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)), ) if status != 0 { return nil, false } return outBuf[:outLen], true } func aesEncrypt(plaintext []byte) (string, string, bool) { if len(plaintext) == 0 { return "", "", false } encBuf := make([]byte, 65536) ivBuf := make([]byte, 64) var encLen, ivLen uint32 status := hostCryptoAesEncrypt( uintptr(unsafe.Pointer(&plaintext[0])), uint32(len(plaintext)), uintptr(unsafe.Pointer(&encBuf[0])), uintptr(unsafe.Pointer(&encLen)), uintptr(unsafe.Pointer(&ivBuf[0])), uintptr(unsafe.Pointer(&ivLen)), ) if status != 0 { return "", "", false } return string(encBuf[:encLen]), string(ivBuf[:ivLen]), true } func randomBytes(n uint32) (string, bool) { outBuf := make([]byte, n*2+4) // hex = 2 chars per byte var outLen uint32 status := hostCryptoRandomBytes( n, uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)), ) if status != 0 { return "", false } return string(outBuf[:outLen]), true } // hex encodes raw bytes to lowercase hex string func hex(b []byte) string { const hexChars = "0123456789abcdef" out := make([]byte, len(b)*2) for i, v := range b { out[i*2] = hexChars[v>>4] out[i*2+1] = hexChars[v&0xf] } return string(out) } // strings import 只為了 strings.Builder(interpolate 用,這裡不需要但 import 要保留給未來) var _ = strings.Builder{}