- /* Copyright (c) 2018, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
- // convert_wycheproof.go converts Wycheproof test vectors into a format more
- // easily consumed by BoringSSL.
- package main
-
- import (
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "sort"
- "strings"
- )
-
- type wycheproofTest struct {
- Algorithm string `json:"algorithm"`
- GeneratorVersion string `json:"generatorVersion"`
- NumberOfTests int `json:"numberOfTests"`
- Notes map[string]string `json:"notes"`
- Header []string `json:"header"`
- // encoding/json does not support collecting unused keys, so we leave
- // everything past this point as generic.
- TestGroups []map[string]interface{} `json:"testGroups"`
- }
-
- func sortedKeys(m map[string]interface{}) []string {
- keys := make([]string, 0, len(m))
- for k, _ := range m {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- return keys
- }
-
- func printAttribute(w io.Writer, key string, valueI interface{}, isInstruction bool) error {
- switch value := valueI.(type) {
- case float64:
- if float64(int(value)) != value {
- panic(key + "was not an integer.")
- }
- if isInstruction {
- if _, err := fmt.Fprintf(w, "[%s = %d]\n", key, int(value)); err != nil {
- return err
- }
- } else {
- if _, err := fmt.Fprintf(w, "%s = %d\n", key, int(value)); err != nil {
- return err
- }
- }
- case string:
- if strings.Contains(value, "\n") {
- panic(key + " contained a newline.")
- }
- if isInstruction {
- if _, err := fmt.Fprintf(w, "[%s = %s]\n", key, value); err != nil {
- return err
- }
- } else {
- if _, err := fmt.Fprintf(w, "%s = %s\n", key, value); err != nil {
- return err
- }
- }
- case map[string]interface{}:
- for _, k := range sortedKeys(value) {
- if err := printAttribute(w, key+"."+k, value[k], isInstruction); err != nil {
- return err
- }
- }
- default:
- panic(fmt.Sprintf("Unknown type for %q: %T", key, valueI))
- }
- return nil
- }
-
- func printComment(w io.Writer, in string) error {
- const width = 80 - 2
- lines := strings.Split(in, "\n")
- for _, line := range lines {
- for {
- if len(line) <= width {
- if _, err := fmt.Fprintf(w, "# %s\n", line); err != nil {
- return err
- }
- break
- }
-
- // Find the last space we can break at.
- n := strings.LastIndexByte(line[:width+1], ' ')
- if n < 0 {
- // The next word is too long. Wrap as soon as that word ends.
- n = strings.IndexByte(line[width+1:], ' ')
- if n < 0 {
- // This was the last word.
- if _, err := fmt.Fprintf(w, "# %s\n", line); err != nil {
- return nil
- }
- break
- }
- n += width + 1
- }
- if _, err := fmt.Fprintf(w, "# %s\n", line[:n]); err != nil {
- return err
- }
- line = line[n+1:] // Ignore the space.
- }
- }
- return nil
- }
-
- func convertWycheproof(f io.Writer, jsonPath string) error {
- jsonData, err := ioutil.ReadFile(jsonPath)
- if err != nil {
- return err
- }
-
- var w wycheproofTest
- if err := json.Unmarshal(jsonData, &w); err != nil {
- return err
- }
-
- if _, err := fmt.Fprintf(f, `# Imported from Wycheproof's %s.
- # This file is generated by convert_wycheproof.go. Do not edit by hand.
- #
- # Algorithm: %s
- # Generator version: %s
-
- `, jsonPath, w.Algorithm, w.GeneratorVersion); err != nil {
- return err
- }
-
- for _, group := range w.TestGroups {
- for _, k := range sortedKeys(group) {
- // Wycheproof files always include both keyPem and
- // keyDer. Skip keyPem as they contain newlines. We
- // process keyDer more easily.
- if k == "type" || k == "tests" || k == "keyPem" {
- continue
- }
- if err := printAttribute(f, k, group[k], true); err != nil {
- return err
- }
- }
- fmt.Fprintf(f, "\n")
- tests := group["tests"].([]interface{})
- for _, testI := range tests {
- test := testI.(map[string]interface{})
- if _, err := fmt.Fprintf(f, "# tcId = %d\n", int(test["tcId"].(float64))); err != nil {
- return err
- }
- if comment, ok := test["comment"]; ok && len(comment.(string)) != 0 {
- if err := printComment(f, comment.(string)); err != nil {
- return err
- }
- }
- for _, k := range sortedKeys(test) {
- if k == "comment" || k == "flags" || k == "tcId" {
- continue
- }
- if err := printAttribute(f, k, test[k], false); err != nil {
- return err
- }
- }
- if flags, ok := test["flags"]; ok {
- for _, flag := range flags.([]interface{}) {
- if note, ok := w.Notes[flag.(string)]; ok {
- if err := printComment(f, note); err != nil {
- return err
- }
- }
- }
- }
- if _, err := fmt.Fprintf(f, "\n"); err != nil {
- return err
- }
- }
- }
- return nil
- }
-
- var defaultInputs = []string{
- "aes_cbc_pkcs5_test.json",
- "aes_cmac_test.json",
- "aes_gcm_siv_test.json",
- "aes_gcm_test.json",
- "chacha20_poly1305_test.json",
- "dsa_test.json",
- "ecdh_secp224r1_test.json",
- "ecdh_secp256r1_test.json",
- "ecdh_secp384r1_test.json",
- "ecdh_secp521r1_test.json",
- "ecdsa_secp224r1_sha224_test.json",
- "ecdsa_secp224r1_sha256_test.json",
- "ecdsa_secp224r1_sha512_test.json",
- "ecdsa_secp256r1_sha256_test.json",
- "ecdsa_secp256r1_sha512_test.json",
- "ecdsa_secp384r1_sha384_test.json",
- "ecdsa_secp384r1_sha512_test.json",
- "ecdsa_secp521r1_sha512_test.json",
- "eddsa_test.json",
- "kw_test.json",
- "rsa_pss_2048_sha1_mgf1_20_test.json",
- "rsa_pss_2048_sha256_mgf1_0_test.json",
- "rsa_pss_2048_sha256_mgf1_32_test.json",
- "rsa_pss_3072_sha256_mgf1_32_test.json",
- "rsa_pss_4096_sha256_mgf1_32_test.json",
- "rsa_pss_4096_sha512_mgf1_32_test.json",
- "rsa_pss_misc_test.json",
- "rsa_signature_test.json",
- "x25519_test.json",
- }
-
- func main() {
- switch len(os.Args) {
- case 1:
- for _, jsonPath := range defaultInputs {
- if !strings.HasSuffix(jsonPath, ".json") {
- panic(jsonPath)
- }
-
- txtPath := jsonPath[:len(jsonPath)-len(".json")] + ".txt"
- out, err := os.Create(txtPath)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error opening output %s: %s\n", txtPath, err)
- os.Exit(1)
- }
- defer out.Close()
-
- if err := convertWycheproof(out, jsonPath); err != nil {
- fmt.Fprintf(os.Stderr, "Error converting %s: %s\n", jsonPath, err)
- os.Exit(1)
- }
- }
-
- case 2:
- if err := convertWycheproof(os.Stdout, os.Args[1]); err != nil {
- fmt.Fprintf(os.Stderr, "Error converting %s: %s\n", os.Args[1], err)
- os.Exit(1)
- }
-
- default:
- fmt.Fprintf(os.Stderr, "Usage: %s [input JSON]\n", os.Args[0])
- os.Exit(1)
- }
- }
|