1// Copyright 2021 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package hpke 18 19import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "testing" 24 25 "github.com/google/tink/go/subtle" 26) 27 28// TODO(b/201070904): Write tests using internetDraftVector. 29func TestX25519KEMEncapsulateBoringSSLVectors(t *testing.T) { 30 i := 0 31 vecs := baseModeX25519HKDFSHA256Vectors(t) 32 for key, vec := range vecs { 33 if key.mode != baseMode || 34 key.kemID != x25519HKDFSHA256 || 35 key.kdfID != hkdfSHA256 || 36 (key.aeadID != aes128GCM && key.aeadID != aes256GCM && key.aeadID != chaCha20Poly1305) { 37 continue 38 } 39 40 i++ 41 t.Run(fmt.Sprintf("%d", key.id), func(t *testing.T) { 42 kem, err := newKEM(x25519HKDFSHA256) 43 if err != nil { 44 t.Fatal(err) 45 } 46 x25519KEMGeneratePrivateKey = func() ([]byte, error) { 47 return vec.senderPrivKey, nil 48 } 49 50 secret, enc, err := kem.encapsulate(vec.recipientPubKey) 51 if err != nil { 52 t.Errorf("encapsulate for vector %v: got err %q, want success", key, err) 53 } 54 if !bytes.Equal(secret, vec.sharedSecret) { 55 t.Errorf("encapsulate for vector %v: got shared secret %v, want %v", key, secret, vec.sharedSecret) 56 } 57 if !bytes.Equal(enc, vec.encapsulatedKey) { 58 t.Errorf("encapsulate for vector %v: got encapsulated key %v, want %v", key, enc, vec.encapsulatedKey) 59 } 60 }) 61 } 62 x25519KEMGeneratePrivateKey = subtle.GeneratePrivateKeyX25519 63 if i < 2 { 64 t.Errorf("number of vectors tested = %d, want > %d", i, 2) 65 } 66} 67 68func TestX25519KEMEncapsulateBadRecipientPubKey(t *testing.T) { 69 _, v := internetDraftVector(t) 70 kem, err := newKEM(x25519HKDFSHA256) 71 if err != nil { 72 t.Fatal(err) 73 } 74 badRecipientPubKey := append(v.recipientPubKey, []byte("hello")...) 75 if _, _, err := kem.encapsulate(badRecipientPubKey); err == nil { 76 t.Error("encapsulate: got success, want err") 77 } 78} 79 80func TestX25519KEMEncapsulateBadSenderPrivKey(t *testing.T) { 81 _, v := internetDraftVector(t) 82 kem, err := newKEM(x25519HKDFSHA256) 83 if err != nil { 84 t.Fatal(err) 85 } 86 87 x25519KEMPublicFromPrivate = func(privKey []byte) ([]byte, error) { 88 return nil, errors.New("failed to compute public key") 89 } 90 if _, _, err := kem.encapsulate(v.recipientPubKey); err == nil { 91 t.Error("encapsulate: got success, want err") 92 } 93 x25519KEMPublicFromPrivate = subtle.PublicFromPrivateX25519 94} 95 96func TestX25519KEMDecapsulateBoringSSLVectors(t *testing.T) { 97 i := 0 98 vecs := baseModeX25519HKDFSHA256Vectors(t) 99 for key, vec := range vecs { 100 if key.mode != baseMode || 101 key.kemID != x25519HKDFSHA256 || 102 key.kdfID != hkdfSHA256 || 103 (key.aeadID != aes128GCM && key.aeadID != aes256GCM && key.aeadID != chaCha20Poly1305) { 104 continue 105 } 106 107 i++ 108 t.Run(fmt.Sprintf("%d", key.id), func(t *testing.T) { 109 kem, err := newKEM(x25519HKDFSHA256) 110 if err != nil { 111 t.Fatal(err) 112 } 113 secret, err := kem.decapsulate(vec.encapsulatedKey, vec.recipientPrivKey) 114 if err != nil { 115 t.Errorf("decapsulate for vector %v: got err %q, want success", key, err) 116 } 117 if !bytes.Equal(secret, vec.sharedSecret) { 118 t.Errorf("decapsulate for vector %v: got shared secret %v, want %v", key, secret, vec.sharedSecret) 119 } 120 }) 121 } 122 if i < 2 { 123 t.Errorf("number of vectors tested = %d, want > %d", i, 2) 124 } 125} 126 127// TestX25519KEMDecapsulateEncapsulatedKeyPrefixesLargerSlice checks--if the 128// encapsulated key is part of a larger slice, as in HPKE Encrypt 129// https://github.com/google/tink/blob/619b6c1bb1f8573ca56de50cfc6ba23d355670db/go/hybrid/hpke/encrypt.go#L61 130// --that decapsulate does not modify the larger slice. 131func TestX25519KEMDecapsulateEncapsulatedKeyPrefixesLargerSlice(t *testing.T) { 132 _, v := internetDraftVector(t) 133 kem, err := newKEM(x25519HKDFSHA256) 134 if err != nil { 135 t.Fatal(err) 136 } 137 138 largerSlice := make([]byte, 3*len(v.encapsulatedKey)) 139 suffix := largerSlice[len(v.encapsulatedKey):] 140 zeroedSlice := make([]byte, len(suffix)) 141 if !bytes.Equal(suffix, zeroedSlice) { 142 t.Errorf("suffix: got %x, want %x", suffix, zeroedSlice) 143 } 144 145 copy(largerSlice, v.encapsulatedKey) 146 if !bytes.Equal(suffix, zeroedSlice) { 147 t.Errorf("suffix: got %x, want %x", suffix, zeroedSlice) 148 } 149 150 encapsulatedKey := largerSlice[:len(v.encapsulatedKey)] 151 if _, err := kem.decapsulate(encapsulatedKey, v.recipientPrivKey); err != nil { 152 t.Errorf("decapsulate: got err %q, want success", err) 153 } 154 if !bytes.Equal(suffix, zeroedSlice) { 155 t.Errorf("suffix: got %x, want %x", suffix, zeroedSlice) 156 } 157} 158 159func TestX25519KEMDecapsulateBadEncapsulatedKey(t *testing.T) { 160 _, v := internetDraftVector(t) 161 kem, err := newKEM(x25519HKDFSHA256) 162 if err != nil { 163 t.Fatal(err) 164 } 165 badEncapsulatedKey := append(v.encapsulatedKey, []byte("hello")...) 166 if _, err := kem.decapsulate(badEncapsulatedKey, v.recipientPrivKey); err == nil { 167 t.Error("decapsulate: got success, want err") 168 } 169} 170 171func TestX25519KEMDecapsulateBadRecipientPrivKey(t *testing.T) { 172 _, v := internetDraftVector(t) 173 kem, err := newKEM(x25519HKDFSHA256) 174 if err != nil { 175 t.Fatal(err) 176 } 177 badRecipientPrivKey := append(v.recipientPrivKey, []byte("hello")...) 178 if _, err := kem.decapsulate(v.encapsulatedKey, badRecipientPrivKey); err == nil { 179 t.Error("decapsulate: got success, want err") 180 } 181} 182 183func TestX25519KEMEncapsulatedKeyLength(t *testing.T) { 184 kem, err := newKEM(x25519HKDFSHA256) 185 if err != nil { 186 t.Fatal(err) 187 } 188 if kem.encapsulatedKeyLength() != 32 { 189 t.Errorf("encapsulatedKeyLength: got %d, want 32", kem.encapsulatedKeyLength()) 190 } 191} 192