1// Copyright 2022 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 "encoding/hex" 21 "encoding/json" 22 "math/big" 23 "os" 24 "path/filepath" 25 "testing" 26 27 "github.com/google/tink/go/testutil" 28) 29 30// TODO(b/201070904): Separate tests into internal_test package. 31 32// aeadIDs are specified at 33// https://www.rfc-editor.org/rfc/rfc9180.html#section-7.3. 34var aeadIDs = []struct { 35 name string 36 aeadID uint16 37 keyLength int 38}{ 39 {"AES128GCM", aes128GCM, 16}, 40 {"AES256GCM", aes256GCM, 32}, 41 {"ChaCha20Poly1305", chaCha20Poly1305, 32}, 42} 43 44type hpkeID struct { 45 id int 46 mode uint8 47 kemID uint16 48 kdfID uint16 49 aeadID uint16 50} 51 52type vector struct { 53 info []byte 54 senderPubKey []byte 55 senderPrivKey []byte 56 recipientPubKey []byte 57 recipientPrivKey []byte 58 encapsulatedKey []byte 59 sharedSecret []byte 60 keyScheduleCtx []byte 61 secret []byte 62 key []byte 63 baseNonce []byte 64 consecutiveEncryptions []encryptionVector 65 otherEncryptions []encryptionVector 66} 67 68type encryptionVector struct { 69 key []byte 70 plaintext []byte 71 associatedData []byte 72 nonce []byte 73 ciphertext []byte 74 sequenceNumber *big.Int 75} 76 77type encryptionString struct { 78 sequenceNumber uint64 79 plaintext string 80 associatedData string 81 nonce string 82 ciphertext string 83} 84 85// TODO(b/201070904): Include all Tink-supported RFC vectors. 86func internetDraftVector(t *testing.T) (hpkeID, vector) { 87 t.Helper() 88 89 // Test vector from HPKE RFC 90 // https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1.1. 91 v := struct { 92 mode uint8 93 kemID, kdfID, aeadID uint16 94 info, pkEm, skEm, pkRm, skRm, enc, sharedSecret, keyScheduleCtx, secret, key, baseNonce string 95 consecutiveEncryptions, otherEncryptions []encryptionString 96 }{ 97 mode: 0, 98 kemID: 32, 99 kdfID: 1, 100 aeadID: 1, 101 info: "4f6465206f6e2061204772656369616e2055726e", 102 pkEm: "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431", 103 skEm: "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736", 104 pkRm: "3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d", 105 skRm: "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8", 106 enc: "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431", 107 sharedSecret: "fe0e18c9f024ce43799ae393c7e8fe8fce9d218875e8227b0187c04e7d2ea1fc", 108 keyScheduleCtx: "00725611c9d98c07c03f60095cd32d400d8347d45ed67097bbad50fc56da742d07cb6cffde367bb0565ba28bb02c90744a20f5ef37f30523526106f637abb05449", 109 secret: "12fff91991e93b48de37e7daddb52981084bd8aa64289c3788471d9a9712f397", 110 key: "4531685d41d65f03dc48f6b8302c05b0", 111 baseNonce: "56d890e5accaaf011cff4b7d", 112 consecutiveEncryptions: []encryptionString{ 113 { 114 sequenceNumber: 0, 115 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 116 associatedData: "436f756e742d30", 117 nonce: "56d890e5accaaf011cff4b7d", 118 ciphertext: "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a", 119 }, 120 { 121 sequenceNumber: 1, 122 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 123 associatedData: "436f756e742d31", 124 nonce: "56d890e5accaaf011cff4b7c", 125 ciphertext: "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84", 126 }, 127 { 128 sequenceNumber: 2, 129 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 130 associatedData: "436f756e742d32", 131 nonce: "56d890e5accaaf011cff4b7f", 132 ciphertext: "498dfcabd92e8acedc281e85af1cb4e3e31c7dc394a1ca20e173cb72516491588d96a19ad4a683518973dcc180", 133 }, 134 }, 135 otherEncryptions: []encryptionString{ 136 { 137 sequenceNumber: 4, 138 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 139 associatedData: "436f756e742d34", 140 nonce: "56d890e5accaaf011cff4b79", 141 ciphertext: "583bd32bc67a5994bb8ceaca813d369bca7b2a42408cddef5e22f880b631215a09fc0012bc69fccaa251c0246d", 142 }, 143 { 144 sequenceNumber: 255, 145 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 146 associatedData: "436f756e742d323535", 147 nonce: "56d890e5accaaf011cff4b82", 148 ciphertext: "7175db9717964058640a3a11fb9007941a5d1757fda1a6935c805c21af32505bf106deefec4a49ac38d71c9e0a", 149 }, 150 { 151 sequenceNumber: 256, 152 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 153 associatedData: "436f756e742d323536", 154 nonce: "56d890e5accaaf011cff4a7d", 155 ciphertext: "957f9800542b0b8891badb026d79cc54597cb2d225b54c00c5238c25d05c30e3fbeda97d2e0e1aba483a2df9f2", 156 }, 157 }, 158 } 159 160 var info, senderPubKey, senderPrivKey, recipientPubKey, recipientPrivKey, encapsulatedKey, sharedSecret, keyScheduleCtx, secret, key, baseNonce []byte 161 var err error 162 if info, err = hex.DecodeString(v.info); err != nil { 163 t.Fatalf("hex.DecodeString(info): err %q", err) 164 } 165 if senderPubKey, err = hex.DecodeString(v.pkEm); err != nil { 166 t.Fatalf("hex.DecodeString(pkEm): err %q", err) 167 } 168 if senderPrivKey, err = hex.DecodeString(v.skEm); err != nil { 169 t.Fatalf("hex.DecodeString(skEm): err %q", err) 170 } 171 if recipientPubKey, err = hex.DecodeString(v.pkRm); err != nil { 172 t.Fatalf("hex.DecodeString(pkRm): err %q", err) 173 } 174 if recipientPrivKey, err = hex.DecodeString(v.skRm); err != nil { 175 t.Fatalf("hex.DecodeString(skRm): err %q", err) 176 } 177 if encapsulatedKey, err = hex.DecodeString(v.enc); err != nil { 178 t.Fatalf("hex.DecodeString(enc): err %q", err) 179 } 180 if sharedSecret, err = hex.DecodeString(v.sharedSecret); err != nil { 181 t.Fatalf("hex.DecodeString(sharedSecret): err %q", err) 182 } 183 if keyScheduleCtx, err = hex.DecodeString(v.keyScheduleCtx); err != nil { 184 t.Fatalf("hex.DecodeString(keyScheduleCtx): err %q", err) 185 } 186 if secret, err = hex.DecodeString(v.secret); err != nil { 187 t.Fatalf("hex.DecodeString(secret): err %q", err) 188 } 189 if key, err = hex.DecodeString(v.key); err != nil { 190 t.Fatalf("hex.DecodeString(key): err %q", err) 191 } 192 if baseNonce, err = hex.DecodeString(v.baseNonce); err != nil { 193 t.Fatalf("hex.DecodeString(baseNonce): err %q", err) 194 } 195 196 return hpkeID{0 /*=id */, v.mode, v.kemID, v.kdfID, v.aeadID}, 197 vector{ 198 info: info, 199 senderPubKey: senderPubKey, 200 senderPrivKey: senderPrivKey, 201 recipientPubKey: recipientPubKey, 202 recipientPrivKey: recipientPrivKey, 203 encapsulatedKey: encapsulatedKey, 204 sharedSecret: sharedSecret, 205 keyScheduleCtx: keyScheduleCtx, 206 secret: secret, 207 key: key, 208 baseNonce: baseNonce, 209 consecutiveEncryptions: parseEncryptions(t, v.consecutiveEncryptions), 210 otherEncryptions: parseEncryptions(t, v.otherEncryptions), 211 } 212} 213 214func parseEncryptions(t *testing.T, encs []encryptionString) []encryptionVector { 215 t.Helper() 216 217 var res []encryptionVector 218 for _, e := range encs { 219 var plaintext, associatedData, nonce, ciphertext []byte 220 var err error 221 if plaintext, err = hex.DecodeString(e.plaintext); err != nil { 222 t.Fatalf("hex.DecodeString(plaintext): err %q", err) 223 } 224 if associatedData, err = hex.DecodeString(e.associatedData); err != nil { 225 t.Fatalf("hex.DecodeString(associatedData): err %q", err) 226 } 227 if nonce, err = hex.DecodeString(e.nonce); err != nil { 228 t.Fatalf("hex.DecodeString(nonce): err %q", err) 229 } 230 if ciphertext, err = hex.DecodeString(e.ciphertext); err != nil { 231 t.Fatalf("hex.DecodeString(ciphertext): err %q", err) 232 } 233 234 res = append(res, encryptionVector{ 235 plaintext: plaintext, 236 associatedData: associatedData, 237 nonce: nonce, 238 ciphertext: ciphertext, 239 sequenceNumber: big.NewInt(int64(e.sequenceNumber)), 240 }) 241 } 242 243 return res 244} 245 246// aeadRFCVectors returns RFC test vectors for AEAD IDs aes128GCM, aes256GCM, 247// and chaCha20Poly1305. 248func aeadRFCVectors(t *testing.T) map[hpkeID]encryptionVector { 249 t.Helper() 250 251 vecs := []struct { 252 mode uint8 253 kemID, kdfID, aeadID uint16 254 key, plaintext, associatedData, nonce, ciphertext string 255 }{ 256 // https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1.1.1 257 { 258 mode: 0, 259 kemID: 32, 260 kdfID: 1, 261 aeadID: 1, 262 key: "4531685d41d65f03dc48f6b8302c05b0", 263 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 264 associatedData: "436f756e742d30", 265 nonce: "56d890e5accaaf011cff4b7d", 266 ciphertext: "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a", 267 }, 268 { 269 mode: 0, 270 kemID: 32, 271 kdfID: 1, 272 aeadID: 1, 273 key: "4531685d41d65f03dc48f6b8302c05b0", 274 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 275 associatedData: "436f756e742d31", 276 nonce: "56d890e5accaaf011cff4b7c", 277 ciphertext: "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84", 278 }, 279 // https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.6.1.1 280 { 281 mode: 0, 282 kemID: 18, 283 kdfID: 3, 284 aeadID: 2, 285 key: "751e346ce8f0ddb2305c8a2a85c70d5cf559c53093656be636b9406d4d7d1b70", 286 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 287 associatedData: "436f756e742d30", 288 nonce: "55ff7a7d739c69f44b25447b", 289 ciphertext: "170f8beddfe949b75ef9c387e201baf4132fa7374593dfafa90768788b7b2b200aafcc6d80ea4c795a7c5b841a", 290 }, 291 { 292 mode: 0, 293 kemID: 18, 294 kdfID: 3, 295 aeadID: 2, 296 key: "751e346ce8f0ddb2305c8a2a85c70d5cf559c53093656be636b9406d4d7d1b70", 297 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 298 associatedData: "436f756e742d31", 299 nonce: "55ff7a7d739c69f44b25447a", 300 ciphertext: "d9ee248e220ca24ac00bbbe7e221a832e4f7fa64c4fbab3945b6f3af0c5ecd5e16815b328be4954a05fd352256", 301 }, 302 // https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.2.1.1 303 { 304 mode: 0, 305 kemID: 32, 306 kdfID: 1, 307 aeadID: 3, 308 key: "ad2744de8e17f4ebba575b3f5f5a8fa1f69c2a07f6e7500bc60ca6e3e3ec1c91", 309 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 310 associatedData: "436f756e742d30", 311 nonce: "5c4d98150661b848853b547f", 312 ciphertext: "1c5250d8034ec2b784ba2cfd69dbdb8af406cfe3ff938e131f0def8c8b60b4db21993c62ce81883d2dd1b51a28", 313 }, 314 { 315 mode: 0, 316 kemID: 32, 317 kdfID: 1, 318 aeadID: 3, 319 key: "ad2744de8e17f4ebba575b3f5f5a8fa1f69c2a07f6e7500bc60ca6e3e3ec1c91", 320 plaintext: "4265617574792069732074727574682c20747275746820626561757479", 321 associatedData: "436f756e742d31", 322 nonce: "5c4d98150661b848853b547e", 323 ciphertext: "6b53c051e4199c518de79594e1c4ab18b96f081549d45ce015be002090bb119e85285337cc95ba5f59992dc98c", 324 }, 325 } 326 327 m := make(map[hpkeID]encryptionVector) 328 for i, v := range vecs { 329 var key, plaintext, associatedData, nonce, ciphertext []byte 330 var err error 331 if key, err = hex.DecodeString(v.key); err != nil { 332 t.Fatalf("hex.DecodeString(key): err %q", err) 333 } 334 if plaintext, err = hex.DecodeString(v.plaintext); err != nil { 335 t.Fatalf("hex.DecodeString(plaintext): err %q", err) 336 } 337 if associatedData, err = hex.DecodeString(v.associatedData); err != nil { 338 t.Fatalf("hex.DecodeString(associatedData): err %q", err) 339 } 340 if nonce, err = hex.DecodeString(v.nonce); err != nil { 341 t.Fatalf("hex.DecodeString(nonce): err %q", err) 342 } 343 if ciphertext, err = hex.DecodeString(v.ciphertext); err != nil { 344 t.Fatalf("hex.DecodeString(ciphertext): err %q", err) 345 } 346 347 id := hpkeID{i, v.mode, v.kemID, v.kdfID, v.aeadID} 348 m[id] = encryptionVector{ 349 key: key, 350 plaintext: plaintext, 351 associatedData: associatedData, 352 nonce: nonce, 353 ciphertext: ciphertext, 354 } 355 } 356 357 return m 358} 359 360// baseModeX25519HKDFSHA256Vectors returns BoringSSL test vectors for HPKE base 361// mode with Diffie-Hellman-based X25519, HKDF-SHA256 KEM as per 362// https://www.rfc-editor.org/rfc/rfc9180.html#section-7.1. 363func baseModeX25519HKDFSHA256Vectors(t *testing.T) map[hpkeID]vector { 364 testutil.SkipTestIfTestSrcDirIsNotSet(t) 365 t.Helper() 366 367 srcDir, _ := os.LookupEnv("TEST_SRCDIR") 368 path := filepath.Join(srcDir, os.Getenv("TEST_WORKSPACE"), "/testdata/testvectors/hpke_boringssl.json") 369 f, err := os.Open(path) 370 if err != nil { 371 t.Fatal(err) 372 } 373 374 var vecs []struct { 375 Mode uint8 `json:"mode"` 376 KEMID uint16 `json:"kem_id"` 377 KDFID uint16 `json:"kdf_id"` 378 AEADID uint16 `json:"aead_id"` 379 Info testutil.HexBytes `json:"info"` 380 SenderPubKey testutil.HexBytes `json:"pkEm"` 381 SenderPrivKey testutil.HexBytes `json:"skEm"` 382 RecipientPubKey testutil.HexBytes `json:"pkRm"` 383 RecipientPrivKey testutil.HexBytes `json:"skRm"` 384 EncapsulatedKey testutil.HexBytes `json:"enc"` 385 SharedSecret testutil.HexBytes `json:"shared_secret"` 386 KeyScheduleCtx testutil.HexBytes `json:"key_schedule_context"` 387 Secret testutil.HexBytes `json:"secret"` 388 Key testutil.HexBytes `json:"key"` 389 BaseNonce testutil.HexBytes `json:"base_nonce"` 390 } 391 parser := json.NewDecoder(f) 392 if err := parser.Decode(&vecs); err != nil { 393 t.Fatal(err) 394 } 395 396 m := make(map[hpkeID]vector) 397 for i, v := range vecs { 398 if v.Mode != baseMode || v.KEMID != x25519HKDFSHA256 { 399 continue 400 } 401 402 id := hpkeID{i, v.Mode, v.KEMID, v.KDFID, v.AEADID} 403 m[id] = vector{ 404 info: v.Info, 405 senderPubKey: v.SenderPubKey, 406 senderPrivKey: v.SenderPrivKey, 407 recipientPubKey: v.RecipientPubKey, 408 recipientPrivKey: v.RecipientPrivKey, 409 encapsulatedKey: v.EncapsulatedKey, 410 sharedSecret: v.SharedSecret, 411 keyScheduleCtx: v.KeyScheduleCtx, 412 secret: v.Secret, 413 key: v.Key, 414 baseNonce: v.BaseNonce, 415 } 416 } 417 418 return m 419} 420 421func TestHpkeSuiteIDMemoryAllocatedIsExact(t *testing.T) { 422 suiteID := hpkeSuiteID(1, 2, 3) 423 if len(suiteID) != cap(suiteID) { 424 t.Errorf("want len(suiteID) == cap(suiteID), got %d != %d", len(suiteID), cap(suiteID)) 425 } 426} 427 428func TestKeyScheduleContextMemoryAllocatedIsExact(t *testing.T) { 429 context := keyScheduleContext(1, []byte{1, 2, 3}, []byte{1, 2, 3, 4, 5}) 430 if len(context) != cap(context) { 431 t.Errorf("want len(context) == cap(context), got %d != %d", len(context), cap(context)) 432 } 433} 434 435func TestLabelIKMMemoryAllocatedIsExact(t *testing.T) { 436 ikm := labelIKM("abcde", []byte{1, 2, 3}, []byte{1, 2, 3, 4, 5}) 437 if len(ikm) != cap(ikm) { 438 t.Errorf("want len(ikm) == cap(ikm), got %d != %d", len(ikm), cap(ikm)) 439 } 440} 441 442func TestLabelInfoMemoryAllocatedIsExact(t *testing.T) { 443 info, err := labelInfo("abcde", []byte{1, 2, 3}, []byte{1, 2, 3, 4, 5}, 42) 444 if err != nil { 445 t.Errorf("labelInfo() err = %v, want nil", err) 446 } 447 if len(info) != cap(info) { 448 t.Errorf("want len(info) == cap(info), got %d != %d", len(info), cap(info)) 449 } 450} 451