diff --git a/cmd/taler-auditor-offline-signing/main.go b/cmd/taler-auditor-offline-signing/main.go index bbab9fb..2f192c7 100644 --- a/cmd/taler-auditor-offline-signing/main.go +++ b/cmd/taler-auditor-offline-signing/main.go @@ -28,11 +28,9 @@ import ( "os" "regexp" "strconv" - - "github.com/davecgh/go-spew/spew" ) -type Data struct { +type Input struct { Operation string `json:"operation"` Arguments struct { Version string `json:"version"` @@ -90,6 +88,20 @@ func (ep *EdDSAPublicKey) UnmarshalJSON(in []byte) (e error) { return nil } +func (ep *EdDSAPublicKey) MarshalJSON() ([]byte, error) { + enc, e := crockfordEncode([]byte(*ep)) + if e != nil { + return nil, e + } + + buf := make([]byte, len(enc)+2) + buf[0] = '"' + buf[len(buf)-1] = '"' + copy(buf[1:], enc) + + return buf, nil +} + const ( CURRENCY_LEN = 12 CURRENCY_LEN_STR = "12" @@ -246,10 +258,39 @@ func getValue(a byte) int { return -1 } +// Copy of GNUNET_STRINGS_data_to_string from gnunet/src/util/strings.c +func crockfordEncode(in []byte) ([]byte, error) { + const encTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" + + var ( + out []byte + rpos, bits, vbit int + ) + + for rpos < len(in) || vbit > 0 { + if rpos < len(in) && vbit < 5 { + bits = (bits << 8) | int(in[rpos]) // eat 8 more bits + rpos++ + vbit += 8 + } + if vbit < 5 { + bits <<= (5 - vbit) // zero-padding + if vbit != (len(in)*8)%5 { + return nil, fmt.Errorf("vbit (%d) != (len(in)*8)%%5 (%d)", vbit, (len(in)*8)%5) + } + vbit = 5 + } + vbit -= 5 + out = append(out, encTable[(bits>>vbit)&31]) + } + + return out, nil +} + func (es *EdDSASignature) UnmarshalJSON(in []byte) (e error) { var buf []byte - // 1. decode crockford.base32 + // Decode crockford.base32, the Taler flavour if buf, e = crockfordDecode(bytes.Trim(in, `"`)); e != nil { return fmt.Errorf("couldn't decode EdDSASignature as crockford.base32: %v (%v)", e, string(in)) } else if len(buf) != 64 { @@ -262,13 +303,31 @@ func (es *EdDSASignature) UnmarshalJSON(in []byte) (e error) { return nil } +func (es *EdDSASignature) MarshalJSON() (b []byte, e error) { + var buf = make([]byte, len(es.R)+len(es.S)) + copy(buf, es.R) + copy(buf[len(es.R):], es.S) + + enc, err := crockfordEncode(buf) + if err != nil { + return nil, err + } + + b = make([]byte, len(enc)+2) + b[0] = '"' + b[len(b)-1] = '"' + copy(b[1:], enc) + + return b, nil +} + type RSAPublicKey rsa.PublicKey // following gnunet/src/json/json_helper.c and gnunet/src/util/crypto_rsa.c func (ep *RSAPublicKey) UnmarshalJSON(in []byte) (e error) { var buf []byte - // 1. decode crockford.base32 + // 1. decode crockford.base32, the Taler flavour if buf, e = crockfordDecode(bytes.Trim(in, `"`)); e != nil { return fmt.Errorf("couldn't decode EncodedRSAPublicKey as crockford.base32: %v (%v)", e, string(in)) } @@ -296,16 +355,55 @@ func (ep *RSAPublicKey) UnmarshalJSON(in []byte) (e error) { return nil } +func (ep *RSAPublicKey) MarshalJSON() (b []byte, e error) { + nb := ep.N.Bytes() + eb := big.NewInt(int64(ep.E)).Bytes() + if len(nb) > 2<<16-1 || len(eb) > 2<<16-1 { + return nil, fmt.Errorf("values too large") + } + + buf := make([]byte, 4+len(nb)+len(eb)) + binary.BigEndian.PutUint16(buf, uint16(len(nb))) + binary.BigEndian.PutUint16(buf[2:], uint16(len(eb))) + copy(buf[4:], nb) + copy(buf[4+len(nb):], eb) + + enc, err := crockfordEncode(buf) + if err != nil { + return nil, err + } + + b = make([]byte, len(enc)+2) + b[0] = '"' + b[len(b)-1] = '"' + copy(b[1:], enc) + + return b, nil +} + +type Output []SignOperation + +type SignOperation struct { + Operation string `json:"operation"` + Arguments struct { + HDenumPub RSAPublicKey `json:"h_denum_pub"` + AuditorSig EdDSASignature `json:"auditor_sig"` + } `json:"arguments"` +} + func main() { - data := new(Data) + input := new(Input) dec := json.NewDecoder(os.Stdin) - e := dec.Decode(data) + e := dec.Decode(input) if e != nil { log.Fatal(e) } - spew.Dump(data) enc := json.NewEncoder(os.Stdout) - enc.SetIndent("Data:", " ") - enc.Encode(data) + enc.SetIndent("Input:", " ") + e = enc.Encode(input) + if e != nil { + log.Fatal(e) + } + }