From: tb Date: Mon, 20 Aug 2018 17:06:18 +0000 (+0000) Subject: Run the Wycheproof ChaCha20-Poly1305 test vectors against libcrypto. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=867d6e6a2f73ec1f0eeda072299c813575c5bb69;p=openbsd Run the Wycheproof ChaCha20-Poly1305 test vectors against libcrypto. We currently only support nonces of length 12, so skip a few tests. With input from jsing --- diff --git a/regress/lib/libcrypto/wycheproof/wycheproof.go b/regress/lib/libcrypto/wycheproof/wycheproof.go index d1457238774..c00a869f6fd 100644 --- a/regress/lib/libcrypto/wycheproof/wycheproof.go +++ b/regress/lib/libcrypto/wycheproof/wycheproof.go @@ -1,4 +1,4 @@ -/* $OpenBSD: wycheproof.go,v 1.5 2018/08/10 16:22:58 jsing Exp $ */ +/* $OpenBSD: wycheproof.go,v 1.6 2018/08/20 17:06:18 tb Exp $ */ /* * Copyright (c) 2018 Joel Sing * @@ -25,6 +25,7 @@ package main #include #include #include +#include #include #include */ @@ -48,6 +49,27 @@ import ( const testVectorPath = "/usr/local/share/wycheproof/testvectors" +type wycheproofTestGroupChaCha20Poly1305 struct { + IVSize int `json:"ivSize"` + KeySize int `json:"keySize"` + TagSize int `json:"tagSize"` + Type string `json:"type"` + Tests []*wycheproofTestChaCha20Poly1305 `json:"tests"` +} + +type wycheproofTestChaCha20Poly1305 struct { + TCID int `json:"tcId"` + Comment string `json:"comment"` + Key string `json:"key"` + IV string `json:"iv"` + AAD string `json:"aad"` + Msg string `json:"msg"` + CT string `json:"ct"` + Tag string `json:"tag"` + Result string `json:"result"` + Flags []string `json:"flags"` +} + type wycheproofECDSAKey struct { Curve string `json:"curve"` KeySize int `json:"keySize"` @@ -169,6 +191,117 @@ func hashFromString(hs string) (hash.Hash, error) { } } +func runChaCha20Poly1305Test(iv_len int, key_len int, tag_len int, wt *wycheproofTestChaCha20Poly1305) bool { + aead := C.EVP_aead_chacha20_poly1305() + if aead == nil { + log.Fatal("EVP_aead_chacha20_poly1305 failed") + } + + key, err := hex.DecodeString(wt.Key) + if err != nil { + log.Fatalf("Failed to decode key %q: %v", wt.Key, err) + } + if key_len != len(key) { + log.Fatalf("Key length mismatch: got %d, want %d", len(key), key_len) + } + + var ctx C.EVP_AEAD_CTX + if C.EVP_AEAD_CTX_init((*C.EVP_AEAD_CTX)(unsafe.Pointer(&ctx)), aead, (*C.uchar)(unsafe.Pointer(&key[0])), C.size_t(key_len), C.size_t(tag_len), nil) != 1 { + log.Fatalf("Failed to initialize AEAD context") + } + + iv, err := hex.DecodeString(wt.IV) + if err != nil { + log.Fatalf("Failed to decode key %q: %v", wt.IV, err) + } + if iv_len != len(iv) { + log.Fatalf("IV length mismatch: got %d, want %d", len(iv), iv_len) + } + aad, err := hex.DecodeString(wt.AAD) + if err != nil { + log.Fatalf("Failed to decode AAD %q: %v", wt.AAD, err) + } + msg, err := hex.DecodeString(wt.Msg) + if err != nil { + log.Fatalf("Failed to decode msg %q: %v", wt.Msg, err) + } + + ivLen, aadLen, msgLen := len(iv), len(aad), len(msg) + if ivLen == 0 { + iv = append(iv, 0) + } + if aadLen == 0 { + aad = append(aad, 0) + } + if msgLen == 0 { + msg = append(msg, 0) + } + + maxOutLen := msgLen + tag_len + out := make([]byte, maxOutLen) + var outLen C.size_t + + ret := C.EVP_AEAD_CTX_seal((*C.EVP_AEAD_CTX)(unsafe.Pointer(&ctx)), (*C.uint8_t)(unsafe.Pointer(&out[0])), (*C.size_t)(unsafe.Pointer(&outLen)), C.size_t(maxOutLen), (*C.uint8_t)(unsafe.Pointer(&iv[0])), C.size_t(ivLen), (*C.uint8_t)(unsafe.Pointer(&msg[0])), C.size_t(msgLen), (*C.uint8_t)(unsafe.Pointer(&aad[0])), C.size_t(aadLen)) + + C.EVP_AEAD_CTX_cleanup((*C.EVP_AEAD_CTX)(unsafe.Pointer(&ctx))) + + if ret != 1 && wt.Result == "invalid" { + fmt.Printf("INFO: Test case %d (%q) - EVP_AEAD_CTX_seal() = %d, want %v\n", wt.TCID, wt.Comment, int(ret), wt.Result) + return true + } + + if (outLen != C.size_t(maxOutLen)) { + fmt.Printf("FAIL: Test case %d (%q) - ChaCha output length mismatch: got %d, want %d", wt.TCID, wt.Comment, outLen, maxOutLen) + return false + } + + outCt := out[0:msgLen] + outTag := out[msgLen: maxOutLen] + + ct, err := hex.DecodeString(wt.CT) + if err != nil { + log.Fatalf("Failed to decode ct %q: %v", wt.CT, err) + } + if len(ct) != msgLen { + fmt.Printf("FAIL: Test case %d (%q) - msg length %d doesn't match ct length %d", wt.TCID, wt.Comment, msgLen, len(ct)) + return false + } + tag, err := hex.DecodeString(wt.Tag) + if err != nil { + log.Fatalf("Failed to decode tag %q: %v", wt.Tag, err) + } + if len(tag) != tag_len { + fmt.Printf("FAIL: Test case %d (%q) tag length: got %d, want %d", wt.TCID, wt.Comment, len(tag), tag_len) + return false + } + + success := false + if (bytes.Equal(outCt, ct) && bytes.Equal(outTag, tag)) || wt.Result == "invalid" { + success = true + } else { + fmt.Printf("FAIL: Test case %d (%q) - EVP_AEAD_CTX_seal() = %d, ct match: %t, tag match: %t; want %v\n", wt.TCID, wt.Comment, int(ret), bytes.Equal(outCt, ct), bytes.Equal(outTag, tag), wt.Result) + } + + return success +} + +func runChaCha20Poly1305TestGroup(wtg *wycheproofTestGroupChaCha20Poly1305) bool { + // We currently only support nonces of length 12 (96 bits) + if wtg.IVSize != 96 { + return true + } + + fmt.Printf("Running ChaCha20-Poly1305 test group %v with IV size %d, key size %d, tag size %d...\n", wtg.Type, wtg.IVSize, wtg.KeySize, wtg.TagSize) + + success := true + for _, wt := range wtg.Tests { + if !runChaCha20Poly1305Test(wtg.IVSize / 8, wtg.KeySize / 8, wtg.TagSize / 8, wt) { + success = false + } + } + return success +} + func runECDSATest(ecKey *C.EC_KEY, nid int, h hash.Hash, wt *wycheproofTestECDSA) bool { msg, err := hex.DecodeString(wt.Msg) if err != nil { @@ -390,6 +523,8 @@ func runTestVectors(path string) bool { var wtg interface{} switch wtv.Algorithm { + case "CHACHA20-POLY1305": + wtg = &wycheproofTestGroupChaCha20Poly1305{} case "ECDSA": wtg = &wycheproofTestGroupECDSA{} case "RSASig": @@ -406,6 +541,10 @@ func runTestVectors(path string) bool { log.Fatalf("Failed to unmarshal test groups JSON: %v", err) } switch wtv.Algorithm { + case "CHACHA20-POLY1305": + if !runChaCha20Poly1305TestGroup(wtg.(*wycheproofTestGroupChaCha20Poly1305)) { + success = false + } case "ECDSA": if !runECDSATestGroup(wtg.(*wycheproofTestGroupECDSA)) { success = false @@ -437,6 +576,7 @@ func main() { name string pattern string }{ + {"ChaCha20-Poly1305", "chacha20_poly1305_test.json"}, {"ECDSA", "ecdsa_[^w]*test.json"}, // Skip ecdsa_webcrypto_test.json for now. {"RSA signature", "rsa_signature_*test.json"}, {"X25519", "x25519_*test.json"},