github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/p2p/discover/v5_encoding.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discover 18 19 import ( 20 "bytes" 21 "crypto/aes" 22 "crypto/cipher" 23 "crypto/ecdsa" 24 "crypto/elliptic" 25 crand "crypto/rand" 26 "crypto/sha256" 27 "errors" 28 "fmt" 29 "hash" 30 "net" 31 "time" 32 33 "github.com/zhiqiangxu/go-ethereum/common/math" 34 "github.com/zhiqiangxu/go-ethereum/common/mclock" 35 "github.com/zhiqiangxu/go-ethereum/crypto" 36 "github.com/zhiqiangxu/go-ethereum/p2p/enode" 37 "github.com/zhiqiangxu/go-ethereum/p2p/enr" 38 "github.com/zhiqiangxu/go-ethereum/rlp" 39 "golang.org/x/crypto/hkdf" 40 ) 41 42 // TODO concurrent WHOAREYOU tie-breaker 43 // TODO deal with WHOAREYOU amplification factor (min packet size?) 44 // TODO add counter to nonce 45 // TODO rehandshake after X packets 46 47 // Discovery v5 packet types. 48 const ( 49 p_pingV5 byte = iota + 1 50 p_pongV5 51 p_findnodeV5 52 p_nodesV5 53 p_requestTicketV5 54 p_ticketV5 55 p_regtopicV5 56 p_regconfirmationV5 57 p_topicqueryV5 58 p_unknownV5 = byte(255) // any non-decryptable packet 59 p_whoareyouV5 = byte(254) // the WHOAREYOU packet 60 ) 61 62 // Discovery v5 packet structures. 63 type ( 64 // unknownV5 represents any packet that can't be decrypted. 65 unknownV5 struct { 66 AuthTag []byte 67 } 68 69 // WHOAREYOU contains the handshake challenge. 70 whoareyouV5 struct { 71 AuthTag []byte 72 IDNonce [32]byte // To be signed by recipient. 73 RecordSeq uint64 // ENR sequence number of recipient 74 75 node *enode.Node 76 sent mclock.AbsTime 77 } 78 79 // PING is sent during liveness checks. 80 pingV5 struct { 81 ReqID []byte 82 ENRSeq uint64 83 } 84 85 // PONG is the reply to PING. 86 pongV5 struct { 87 ReqID []byte 88 ENRSeq uint64 89 ToIP net.IP // These fields should mirror the UDP envelope address of the ping 90 ToPort uint16 // packet, which provides a way to discover the the external address (after NAT). 91 } 92 93 // FINDNODE is a query for nodes in the given bucket. 94 findnodeV5 struct { 95 ReqID []byte 96 Distance uint 97 } 98 99 // NODES is the reply to FINDNODE and TOPICQUERY. 100 nodesV5 struct { 101 ReqID []byte 102 Total uint8 103 Nodes []*enr.Record 104 } 105 106 // REQUESTTICKET requests a ticket for a topic queue. 107 requestTicketV5 struct { 108 ReqID []byte 109 Topic []byte 110 } 111 112 // TICKET is the response to REQUESTTICKET. 113 ticketV5 struct { 114 ReqID []byte 115 Ticket []byte 116 } 117 118 // REGTOPIC registers the sender in a topic queue using a ticket. 119 regtopicV5 struct { 120 ReqID []byte 121 Ticket []byte 122 ENR *enr.Record 123 } 124 125 // REGCONFIRMATION is the reply to REGTOPIC. 126 regconfirmationV5 struct { 127 ReqID []byte 128 Registered bool 129 } 130 131 // TOPICQUERY asks for nodes with the given topic. 132 topicqueryV5 struct { 133 ReqID []byte 134 Topic []byte 135 } 136 ) 137 138 const ( 139 // Encryption/authentication parameters. 140 authSchemeName = "gcm" 141 aesKeySize = 16 142 gcmNonceSize = 12 143 idNoncePrefix = "discovery-id-nonce" 144 handshakeTimeout = time.Second 145 ) 146 147 var ( 148 errTooShort = errors.New("packet too short") 149 errUnexpectedHandshake = errors.New("unexpected auth response, not in handshake") 150 errHandshakeNonceMismatch = errors.New("wrong nonce in auth response") 151 errInvalidAuthKey = errors.New("invalid ephemeral pubkey") 152 errUnknownAuthScheme = errors.New("unknown auth scheme in handshake") 153 errNoRecord = errors.New("expected ENR in handshake but none sent") 154 errInvalidNonceSig = errors.New("invalid ID nonce signature") 155 zeroNonce = make([]byte, gcmNonceSize) 156 ) 157 158 // wireCodec encodes and decodes discovery v5 packets. 159 type wireCodec struct { 160 sha256 hash.Hash 161 localnode *enode.LocalNode 162 privkey *ecdsa.PrivateKey 163 myChtagHash enode.ID 164 myWhoareyouMagic []byte 165 166 sc *sessionCache 167 } 168 169 type handshakeSecrets struct { 170 writeKey, readKey, authRespKey []byte 171 } 172 173 type authHeader struct { 174 authHeaderList 175 isHandshake bool 176 } 177 178 type authHeaderList struct { 179 Auth []byte // authentication info of packet 180 IDNonce [32]byte // IDNonce of WHOAREYOU 181 Scheme string // name of encryption/authentication scheme 182 EphemeralKey []byte // ephemeral public key 183 Response []byte // encrypted authResponse 184 } 185 186 type authResponse struct { 187 Version uint 188 Signature []byte 189 Record *enr.Record `rlp:"nil"` // sender's record 190 } 191 192 func (h *authHeader) DecodeRLP(r *rlp.Stream) error { 193 k, _, err := r.Kind() 194 if err != nil { 195 return err 196 } 197 if k == rlp.Byte || k == rlp.String { 198 return r.Decode(&h.Auth) 199 } 200 h.isHandshake = true 201 return r.Decode(&h.authHeaderList) 202 } 203 204 // ephemeralKey decodes the ephemeral public key in the header. 205 func (h *authHeaderList) ephemeralKey(curve elliptic.Curve) *ecdsa.PublicKey { 206 var key encPubkey 207 copy(key[:], h.EphemeralKey) 208 pubkey, _ := decodePubkey(curve, key) 209 return pubkey 210 } 211 212 // newWireCodec creates a wire codec. 213 func newWireCodec(ln *enode.LocalNode, key *ecdsa.PrivateKey, clock mclock.Clock) *wireCodec { 214 c := &wireCodec{ 215 sha256: sha256.New(), 216 localnode: ln, 217 privkey: key, 218 sc: newSessionCache(1024, clock), 219 } 220 // Create magic strings for packet matching. 221 self := ln.ID() 222 c.myWhoareyouMagic = c.sha256sum(self[:], []byte("WHOAREYOU")) 223 copy(c.myChtagHash[:], c.sha256sum(self[:])) 224 return c 225 } 226 227 // encode encodes a packet to a node. 'id' and 'addr' specify the destination node. The 228 // 'challenge' parameter should be the most recently received WHOAREYOU packet from that 229 // node. 230 func (c *wireCodec) encode(id enode.ID, addr string, packet packetV5, challenge *whoareyouV5) ([]byte, []byte, error) { 231 if packet.kind() == p_whoareyouV5 { 232 p := packet.(*whoareyouV5) 233 enc, err := c.encodeWhoareyou(id, p) 234 if err == nil { 235 c.sc.storeSentHandshake(id, addr, p) 236 } 237 return enc, nil, err 238 } 239 // Ensure calling code sets node if needed. 240 if challenge != nil && challenge.node == nil { 241 panic("BUG: missing challenge.node in encode") 242 } 243 writeKey := c.sc.writeKey(id, addr) 244 if writeKey != nil || challenge != nil { 245 return c.encodeEncrypted(id, addr, packet, writeKey, challenge) 246 } 247 return c.encodeRandom(id) 248 } 249 250 // encodeRandom encodes a random packet. 251 func (c *wireCodec) encodeRandom(toID enode.ID) ([]byte, []byte, error) { 252 tag := xorTag(c.sha256sum(toID[:]), c.localnode.ID()) 253 r := make([]byte, 44) // TODO randomize size 254 if _, err := crand.Read(r); err != nil { 255 return nil, nil, err 256 } 257 nonce := make([]byte, gcmNonceSize) 258 if _, err := crand.Read(nonce); err != nil { 259 return nil, nil, fmt.Errorf("can't get random data: %v", err) 260 } 261 b := new(bytes.Buffer) 262 b.Write(tag[:]) 263 rlp.Encode(b, nonce) 264 b.Write(r) 265 return b.Bytes(), nonce, nil 266 } 267 268 // encodeWhoareyou encodes WHOAREYOU. 269 func (c *wireCodec) encodeWhoareyou(toID enode.ID, packet *whoareyouV5) ([]byte, error) { 270 // Sanity check node field to catch misbehaving callers. 271 if packet.RecordSeq > 0 && packet.node == nil { 272 panic("BUG: missing node in whoareyouV5 with non-zero seq") 273 } 274 b := new(bytes.Buffer) 275 b.Write(c.sha256sum(toID[:], []byte("WHOAREYOU"))) 276 err := rlp.Encode(b, packet) 277 return b.Bytes(), err 278 } 279 280 // encodeEncrypted encodes an encrypted packet. 281 func (c *wireCodec) encodeEncrypted(toID enode.ID, toAddr string, packet packetV5, writeKey []byte, challenge *whoareyouV5) (enc []byte, authTag []byte, err error) { 282 nonce := make([]byte, gcmNonceSize) 283 if _, err := crand.Read(nonce); err != nil { 284 return nil, nil, fmt.Errorf("can't get random data: %v", err) 285 } 286 287 var headEnc []byte 288 if challenge == nil { 289 // Regular packet, use existing key and simply encode nonce. 290 headEnc, _ = rlp.EncodeToBytes(nonce) 291 } else { 292 // We're answering WHOAREYOU, generate new keys and encrypt with those. 293 header, sec, err := c.makeAuthHeader(nonce, challenge) 294 if err != nil { 295 return nil, nil, err 296 } 297 if headEnc, err = rlp.EncodeToBytes(header); err != nil { 298 return nil, nil, err 299 } 300 c.sc.storeNewSession(toID, toAddr, sec.readKey, sec.writeKey) 301 writeKey = sec.writeKey 302 } 303 304 // Encode the packet. 305 body := new(bytes.Buffer) 306 body.WriteByte(packet.kind()) 307 if err := rlp.Encode(body, packet); err != nil { 308 return nil, nil, err 309 } 310 tag := xorTag(c.sha256sum(toID[:]), c.localnode.ID()) 311 headsize := len(tag) + len(headEnc) 312 headbuf := make([]byte, headsize) 313 copy(headbuf[:], tag[:]) 314 copy(headbuf[len(tag):], headEnc) 315 316 // Encrypt the body. 317 enc, err = encryptGCM(headbuf, writeKey, nonce, body.Bytes(), tag[:]) 318 return enc, nonce, err 319 } 320 321 // encodeAuthHeader creates the auth header on a call packet following WHOAREYOU. 322 func (c *wireCodec) makeAuthHeader(nonce []byte, challenge *whoareyouV5) (*authHeaderList, *handshakeSecrets, error) { 323 resp := &authResponse{Version: 5} 324 325 // Add our record to response if it's newer than what remote 326 // side has. 327 ln := c.localnode.Node() 328 if challenge.RecordSeq < ln.Seq() { 329 resp.Record = ln.Record() 330 } 331 332 // Create the ephemeral key. This needs to be first because the 333 // key is part of the ID nonce signature. 334 var remotePubkey = new(ecdsa.PublicKey) 335 if err := challenge.node.Load((*enode.Secp256k1)(remotePubkey)); err != nil { 336 return nil, nil, fmt.Errorf("can't find secp256k1 key for recipient") 337 } 338 ephkey, err := crypto.GenerateKey() 339 if err != nil { 340 return nil, nil, fmt.Errorf("can't generate ephemeral key") 341 } 342 ephpubkey := encodePubkey(&ephkey.PublicKey) 343 344 // Add ID nonce signature to response. 345 idsig, err := c.signIDNonce(challenge.IDNonce[:], ephpubkey[:]) 346 if err != nil { 347 return nil, nil, fmt.Errorf("can't sign: %v", err) 348 } 349 resp.Signature = idsig 350 351 // Create session keys. 352 sec := c.deriveKeys(c.localnode.ID(), challenge.node.ID(), ephkey, remotePubkey, challenge) 353 if sec == nil { 354 return nil, nil, fmt.Errorf("key derivation failed") 355 } 356 357 // Encrypt the authentication response and assemble the auth header. 358 respRLP, err := rlp.EncodeToBytes(resp) 359 if err != nil { 360 return nil, nil, fmt.Errorf("can't encode auth response: %v", err) 361 } 362 respEnc, err := encryptGCM(nil, sec.authRespKey, zeroNonce, respRLP, nil) 363 if err != nil { 364 return nil, nil, fmt.Errorf("can't encrypt auth response: %v", err) 365 } 366 head := &authHeaderList{ 367 Auth: nonce, 368 Scheme: authSchemeName, 369 IDNonce: challenge.IDNonce, 370 EphemeralKey: ephpubkey[:], 371 Response: respEnc, 372 } 373 return head, sec, err 374 } 375 376 // deriveKeys generates session keys using elliptic-curve Diffie-Hellman key agreement. 377 func (c *wireCodec) deriveKeys(n1, n2 enode.ID, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, challenge *whoareyouV5) *handshakeSecrets { 378 eph := ecdh(priv, pub) 379 if eph == nil { 380 return nil 381 } 382 383 info := []byte("discovery v5 key agreement") 384 info = append(info, n1[:]...) 385 info = append(info, n2[:]...) 386 kdf := hkdf.New(c.sha256reset, eph, challenge.IDNonce[:], info) 387 sec := handshakeSecrets{ 388 writeKey: make([]byte, aesKeySize), 389 readKey: make([]byte, aesKeySize), 390 authRespKey: make([]byte, aesKeySize), 391 } 392 kdf.Read(sec.writeKey) 393 kdf.Read(sec.readKey) 394 kdf.Read(sec.authRespKey) 395 for i := range eph { 396 eph[i] = 0 397 } 398 return &sec 399 } 400 401 // signIDNonce creates the ID nonce signature. 402 func (c *wireCodec) signIDNonce(nonce, ephkey []byte) ([]byte, error) { 403 idsig, err := crypto.Sign(c.idNonceHash(nonce, ephkey), c.privkey) 404 if err != nil { 405 return nil, fmt.Errorf("can't sign: %v", err) 406 } 407 return idsig[:len(idsig)-1], nil // remove recovery ID 408 } 409 410 // idNonceHash computes the hash of id nonce with prefix. 411 func (c *wireCodec) idNonceHash(nonce, ephkey []byte) []byte { 412 h := c.sha256reset() 413 h.Write([]byte(idNoncePrefix)) 414 h.Write(nonce) 415 h.Write(ephkey) 416 return h.Sum(nil) 417 } 418 419 // decode decodes a discovery packet. 420 func (c *wireCodec) decode(input []byte, addr string) (enode.ID, *enode.Node, packetV5, error) { 421 // Delete timed-out handshakes. This must happen before decoding to avoid 422 // processing the same handshake twice. 423 c.sc.handshakeGC() 424 425 if len(input) < 32 { 426 return enode.ID{}, nil, nil, errTooShort 427 } 428 if bytes.HasPrefix(input, c.myWhoareyouMagic) { 429 p, err := c.decodeWhoareyou(input) 430 return enode.ID{}, nil, p, err 431 } 432 sender := xorTag(input[:32], c.myChtagHash) 433 p, n, err := c.decodeEncrypted(sender, addr, input) 434 return sender, n, p, err 435 } 436 437 // decodeWhoareyou decode a WHOAREYOU packet. 438 func (c *wireCodec) decodeWhoareyou(input []byte) (packetV5, error) { 439 packet := new(whoareyouV5) 440 err := rlp.DecodeBytes(input[32:], packet) 441 return packet, err 442 } 443 444 // decodeEncrypted decodes an encrypted discovery packet. 445 func (c *wireCodec) decodeEncrypted(fromID enode.ID, fromAddr string, input []byte) (packetV5, *enode.Node, error) { 446 // Decode packet header. 447 var head authHeader 448 r := bytes.NewReader(input[32:]) 449 err := rlp.Decode(r, &head) 450 if err != nil { 451 return nil, nil, err 452 } 453 454 // Decrypt and process auth response. 455 readKey, node, err := c.decodeAuth(fromID, fromAddr, &head) 456 if err != nil { 457 return nil, nil, err 458 } 459 460 // Decrypt and decode the packet body. 461 headsize := len(input) - r.Len() 462 bodyEnc := input[headsize:] 463 body, err := decryptGCM(readKey, head.Auth, bodyEnc, input[:32]) 464 if err != nil { 465 if !head.isHandshake { 466 // Can't decrypt, start handshake. 467 return &unknownV5{AuthTag: head.Auth}, nil, nil 468 } 469 return nil, nil, fmt.Errorf("handshake failed: %v", err) 470 } 471 if len(body) == 0 { 472 return nil, nil, errTooShort 473 } 474 p, err := decodePacketBodyV5(body[0], body[1:]) 475 return p, node, err 476 } 477 478 // decodeAuth processes an auth header. 479 func (c *wireCodec) decodeAuth(fromID enode.ID, fromAddr string, head *authHeader) ([]byte, *enode.Node, error) { 480 if !head.isHandshake { 481 return c.sc.readKey(fromID, fromAddr), nil, nil 482 } 483 484 // Remote is attempting handshake. Verify against our last WHOAREYOU. 485 challenge := c.sc.getHandshake(fromID, fromAddr) 486 if challenge == nil { 487 return nil, nil, errUnexpectedHandshake 488 } 489 if head.IDNonce != challenge.IDNonce { 490 return nil, nil, errHandshakeNonceMismatch 491 } 492 sec, n, err := c.decodeAuthResp(fromID, fromAddr, &head.authHeaderList, challenge) 493 if err != nil { 494 return nil, n, err 495 } 496 // Swap keys to match remote. 497 sec.readKey, sec.writeKey = sec.writeKey, sec.readKey 498 c.sc.storeNewSession(fromID, fromAddr, sec.readKey, sec.writeKey) 499 c.sc.deleteHandshake(fromID, fromAddr) 500 return sec.readKey, n, err 501 } 502 503 // decodeAuthResp decodes and verifies an authentication response. 504 func (c *wireCodec) decodeAuthResp(fromID enode.ID, fromAddr string, head *authHeaderList, challenge *whoareyouV5) (*handshakeSecrets, *enode.Node, error) { 505 // Decrypt / decode the response. 506 if head.Scheme != authSchemeName { 507 return nil, nil, errUnknownAuthScheme 508 } 509 ephkey := head.ephemeralKey(c.privkey.Curve) 510 if ephkey == nil { 511 return nil, nil, errInvalidAuthKey 512 } 513 sec := c.deriveKeys(fromID, c.localnode.ID(), c.privkey, ephkey, challenge) 514 respPT, err := decryptGCM(sec.authRespKey, zeroNonce, head.Response, nil) 515 if err != nil { 516 return nil, nil, fmt.Errorf("can't decrypt auth response header: %v", err) 517 } 518 var resp authResponse 519 if err := rlp.DecodeBytes(respPT, &resp); err != nil { 520 return nil, nil, fmt.Errorf("invalid auth response: %v", err) 521 } 522 523 // Verify response node record. The remote node should include the record 524 // if we don't have one or if ours is older than the latest version. 525 node := challenge.node 526 if resp.Record != nil { 527 if node == nil || node.Seq() < resp.Record.Seq() { 528 n, err := enode.New(enode.ValidSchemes, resp.Record) 529 if err != nil { 530 return nil, nil, fmt.Errorf("invalid node record: %v", err) 531 } 532 if n.ID() != fromID { 533 return nil, nil, fmt.Errorf("record in auth respose has wrong ID: %v", n.ID()) 534 } 535 node = n 536 } 537 } 538 if node == nil { 539 return nil, nil, errNoRecord 540 } 541 542 // Verify ID nonce signature. 543 err = c.verifyIDSignature(challenge.IDNonce[:], head.EphemeralKey, resp.Signature, node) 544 if err != nil { 545 return nil, nil, err 546 } 547 return sec, node, nil 548 } 549 550 // verifyIDSignature checks that signature over idnonce was made by the node with given record. 551 func (c *wireCodec) verifyIDSignature(nonce, ephkey, sig []byte, n *enode.Node) error { 552 switch idscheme := n.Record().IdentityScheme(); idscheme { 553 case "v4": 554 var pk ecdsa.PublicKey 555 n.Load((*enode.Secp256k1)(&pk)) // cannot fail because record is valid 556 if !crypto.VerifySignature(crypto.FromECDSAPub(&pk), c.idNonceHash(nonce, ephkey), sig) { 557 return errInvalidNonceSig 558 } 559 return nil 560 default: 561 return fmt.Errorf("can't verify ID nonce signature against scheme %q", idscheme) 562 } 563 } 564 565 // decodePacketBody decodes the body of an encrypted discovery packet. 566 func decodePacketBodyV5(ptype byte, body []byte) (packetV5, error) { 567 var dec packetV5 568 switch ptype { 569 case p_pingV5: 570 dec = new(pingV5) 571 case p_pongV5: 572 dec = new(pongV5) 573 case p_findnodeV5: 574 dec = new(findnodeV5) 575 case p_nodesV5: 576 dec = new(nodesV5) 577 case p_requestTicketV5: 578 dec = new(requestTicketV5) 579 case p_ticketV5: 580 dec = new(ticketV5) 581 case p_regtopicV5: 582 dec = new(regtopicV5) 583 case p_regconfirmationV5: 584 dec = new(regconfirmationV5) 585 case p_topicqueryV5: 586 dec = new(topicqueryV5) 587 default: 588 return nil, fmt.Errorf("unknown packet type %d", ptype) 589 } 590 if err := rlp.DecodeBytes(body, dec); err != nil { 591 return nil, err 592 } 593 return dec, nil 594 } 595 596 // sha256reset returns the shared hash instance. 597 func (c *wireCodec) sha256reset() hash.Hash { 598 c.sha256.Reset() 599 return c.sha256 600 } 601 602 // sha256sum computes sha256 on the concatenation of inputs. 603 func (c *wireCodec) sha256sum(inputs ...[]byte) []byte { 604 c.sha256.Reset() 605 for _, b := range inputs { 606 c.sha256.Write(b) 607 } 608 return c.sha256.Sum(nil) 609 } 610 611 func xorTag(a []byte, b enode.ID) enode.ID { 612 var r enode.ID 613 for i := range r { 614 r[i] = a[i] ^ b[i] 615 } 616 return r 617 } 618 619 // ecdh creates a shared secret. 620 func ecdh(privkey *ecdsa.PrivateKey, pubkey *ecdsa.PublicKey) []byte { 621 secX, secY := pubkey.ScalarMult(pubkey.X, pubkey.Y, privkey.D.Bytes()) 622 if secX == nil { 623 return nil 624 } 625 sec := make([]byte, 33) 626 sec[0] = 0x02 | byte(secY.Bit(0)) 627 math.ReadBits(secX, sec[1:]) 628 return sec 629 } 630 631 // encryptGCM encrypts pt using AES-GCM with the given key and nonce. 632 func encryptGCM(dest, key, nonce, pt, authData []byte) ([]byte, error) { 633 block, err := aes.NewCipher(key) 634 if err != nil { 635 panic(fmt.Errorf("can't create block cipher: %v", err)) 636 } 637 aesgcm, err := cipher.NewGCMWithNonceSize(block, gcmNonceSize) 638 if err != nil { 639 panic(fmt.Errorf("can't create GCM: %v", err)) 640 } 641 return aesgcm.Seal(dest, nonce, pt, authData), nil 642 } 643 644 // decryptGCM decrypts ct using AES-GCM with the given key and nonce. 645 func decryptGCM(key, nonce, ct, authData []byte) ([]byte, error) { 646 block, err := aes.NewCipher(key) 647 if err != nil { 648 return nil, fmt.Errorf("can't create block cipher: %v", err) 649 } 650 if len(nonce) != gcmNonceSize { 651 return nil, fmt.Errorf("invalid GCM nonce size: %d", len(nonce)) 652 } 653 aesgcm, err := cipher.NewGCMWithNonceSize(block, gcmNonceSize) 654 if err != nil { 655 return nil, fmt.Errorf("can't create GCM: %v", err) 656 } 657 pt := make([]byte, 0, len(ct)) 658 return aesgcm.Open(pt, nonce, ct, authData) 659 }