| // Copyright 2018 The BoringSSL Authors | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     https://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | // convert_wycheproof converts Wycheproof test vectors into a format more easily | 
 | // consumed by BoringSSL. | 
 | package main | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"os" | 
 | 	"sort" | 
 | 	"strings" | 
 | ) | 
 |  | 
 | type wycheproofTest struct { | 
 | 	Algorithm        string   `json:"algorithm"` | 
 | 	GeneratorVersion string   `json:"generatorVersion"` | 
 | 	NumberOfTests    int      `json:"numberOfTests"` | 
 | 	Header           []string `json:"header"` | 
 | 	// encoding/json does not support collecting unused keys, so we leave | 
 | 	// everything past this point as generic. | 
 | 	TestGroups []map[string]any `json:"testGroups"` | 
 | } | 
 |  | 
 | func sortedKeys(m map[string]any) []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, valueAny any, isInstruction bool) error { | 
 | 	switch value := valueAny.(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]any: | 
 | 		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, valueAny)) | 
 | 	} | 
 | 	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 := os.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 include keys in multiple formats. Skip PEM and | 
 | 			// JWK formats. We process DER more easily. PEM has newlines and | 
 | 			// JWK is a JSON object. | 
 | 			if k == "type" || k == "tests" || strings.HasSuffix(k, "Pem") || strings.HasSuffix(k, "Jwk") || k == "jwk" { | 
 | 				continue | 
 | 			} | 
 | 			if err := printAttribute(f, k, group[k], true); err != nil { | 
 | 				return err | 
 | 			} | 
 | 		} | 
 | 		fmt.Fprintf(f, "\n") | 
 | 		tests := group["tests"].([]any) | 
 | 		for _, testAny := range tests { | 
 | 			test := testAny.(map[string]any) | 
 | 			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 flagsAny, ok := test["flags"]; ok { | 
 | 				var flags []string | 
 | 				for _, flagAny := range flagsAny.([]any) { | 
 | 					flag := flagAny.(string) | 
 | 					flags = append(flags, flag) | 
 | 				} | 
 | 				if len(flags) != 0 { | 
 | 					if err := printAttribute(f, "flags", strings.Join(flags, ","), false); 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_eax_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", | 
 | 	"hkdf_sha1_test.json", | 
 | 	"hkdf_sha256_test.json", | 
 | 	"hkdf_sha384_test.json", | 
 | 	"hkdf_sha512_test.json", | 
 | 	"hmac_sha1_test.json", | 
 | 	"hmac_sha224_test.json", | 
 | 	"hmac_sha256_test.json", | 
 | 	"hmac_sha384_test.json", | 
 | 	"hmac_sha512_test.json", | 
 | 	"kw_test.json", | 
 | 	"kwp_test.json", | 
 | 	"primality_test.json", | 
 | 	"rsa_oaep_2048_sha1_mgf1sha1_test.json", | 
 | 	"rsa_oaep_2048_sha224_mgf1sha1_test.json", | 
 | 	"rsa_oaep_2048_sha224_mgf1sha224_test.json", | 
 | 	"rsa_oaep_2048_sha256_mgf1sha1_test.json", | 
 | 	"rsa_oaep_2048_sha256_mgf1sha256_test.json", | 
 | 	"rsa_oaep_2048_sha384_mgf1sha1_test.json", | 
 | 	"rsa_oaep_2048_sha384_mgf1sha384_test.json", | 
 | 	"rsa_oaep_2048_sha512_mgf1sha1_test.json", | 
 | 	"rsa_oaep_2048_sha512_mgf1sha512_test.json", | 
 | 	"rsa_oaep_3072_sha256_mgf1sha1_test.json", | 
 | 	"rsa_oaep_3072_sha256_mgf1sha256_test.json", | 
 | 	"rsa_oaep_3072_sha512_mgf1sha1_test.json", | 
 | 	"rsa_oaep_3072_sha512_mgf1sha512_test.json", | 
 | 	"rsa_oaep_4096_sha256_mgf1sha1_test.json", | 
 | 	"rsa_oaep_4096_sha256_mgf1sha256_test.json", | 
 | 	"rsa_oaep_4096_sha512_mgf1sha1_test.json", | 
 | 	"rsa_oaep_4096_sha512_mgf1sha512_test.json", | 
 | 	"rsa_oaep_misc_test.json", | 
 | 	"rsa_pkcs1_2048_test.json", | 
 | 	"rsa_pkcs1_3072_test.json", | 
 | 	"rsa_pkcs1_4096_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_sig_gen_misc_test.json", | 
 | 	"rsa_signature_2048_sha224_test.json", | 
 | 	"rsa_signature_2048_sha256_test.json", | 
 | 	"rsa_signature_2048_sha384_test.json", | 
 | 	"rsa_signature_2048_sha512_test.json", | 
 | 	"rsa_signature_3072_sha256_test.json", | 
 | 	"rsa_signature_3072_sha384_test.json", | 
 | 	"rsa_signature_3072_sha512_test.json", | 
 | 	"rsa_signature_4096_sha384_test.json", | 
 | 	"rsa_signature_4096_sha512_test.json", | 
 | 	"rsa_signature_test.json", | 
 | 	"x25519_test.json", | 
 | 	"xchacha20_poly1305_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) | 
 | 	} | 
 | } |