Mirror of BoringSSL (grpc依赖)
https://boringssl.googlesource.com/boringssl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.4 KiB
137 lines
4.4 KiB
// Copyright (c) 2020, Google Inc. |
|
// |
|
// Permission to use, copy, modify, and/or distribute this software for any |
|
// purpose with or without fee is hereby granted, provided that the above |
|
// copyright notice and this permission notice appear in all copies. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
|
|
package hpke |
|
|
|
import ( |
|
"crypto" |
|
"crypto/rand" |
|
|
|
"golang.org/x/crypto/curve25519" |
|
"golang.org/x/crypto/hkdf" |
|
) |
|
|
|
const ( |
|
rfcLabel string = "HPKE-07" |
|
) |
|
|
|
func getKDFHash(kdfID uint16) crypto.Hash { |
|
switch kdfID { |
|
case HKDFSHA256: |
|
return crypto.SHA256 |
|
case HKDFSHA384: |
|
return crypto.SHA384 |
|
case HKDFSHA512: |
|
return crypto.SHA512 |
|
} |
|
panic("unknown KDF") |
|
} |
|
|
|
func labeledExtract(kdfHash crypto.Hash, salt, suiteID, label, ikm []byte) []byte { |
|
var labeledIKM []byte |
|
labeledIKM = append(labeledIKM, rfcLabel...) |
|
labeledIKM = append(labeledIKM, suiteID...) |
|
labeledIKM = append(labeledIKM, label...) |
|
labeledIKM = append(labeledIKM, ikm...) |
|
return hkdf.Extract(kdfHash.New, labeledIKM, salt) |
|
} |
|
|
|
func labeledExpand(kdfHash crypto.Hash, prk, suiteID, label, info []byte, length int) []byte { |
|
lengthU16 := uint16(length) |
|
if int(lengthU16) != length { |
|
panic("length must be a valid uint16 value") |
|
} |
|
|
|
var labeledInfo []byte |
|
labeledInfo = appendBigEndianUint16(labeledInfo, lengthU16) |
|
labeledInfo = append(labeledInfo, rfcLabel...) |
|
labeledInfo = append(labeledInfo, suiteID...) |
|
labeledInfo = append(labeledInfo, label...) |
|
labeledInfo = append(labeledInfo, info...) |
|
|
|
reader := hkdf.Expand(kdfHash.New, prk, labeledInfo) |
|
key := make([]uint8, length) |
|
_, err := reader.Read(key) |
|
if err != nil { |
|
panic("failed to perform HKDF expand operation") |
|
} |
|
return key |
|
} |
|
|
|
// GenerateKeyPair generates a random key pair. |
|
func GenerateKeyPair() (publicKey, secretKeyOut []byte, err error) { |
|
// Generate a new private key. |
|
var secretKey [curve25519.ScalarSize]byte |
|
_, err = rand.Read(secretKey[:]) |
|
if err != nil { |
|
return |
|
} |
|
// Compute the corresponding public key. |
|
publicKey, err = curve25519.X25519(secretKey[:], curve25519.Basepoint) |
|
if err != nil { |
|
return |
|
} |
|
return publicKey, secretKey[:], nil |
|
} |
|
|
|
// x25519Encap returns an ephemeral, fixed-length symmetric key |sharedSecret| |
|
// and a fixed-length encapsulation of that key |enc| that can be decapsulated |
|
// by the receiver with the secret key corresponding to |publicKeyR|. |
|
// Internally, |keygenOptional| is used to generate an ephemeral keypair. If |
|
// |keygenOptional| is nil, |GenerateKeyPair| will be substituted. |
|
func x25519Encap(publicKeyR []byte, keygen GenerateKeyPairFunc) ([]byte, []byte, error) { |
|
if keygen == nil { |
|
keygen = GenerateKeyPair |
|
} |
|
publicKeyEphem, secretKeyEphem, err := keygen() |
|
if err != nil { |
|
return nil, nil, err |
|
} |
|
dh, err := curve25519.X25519(secretKeyEphem, publicKeyR) |
|
if err != nil { |
|
return nil, nil, err |
|
} |
|
sharedSecret := extractAndExpand(dh, publicKeyEphem, publicKeyR) |
|
return sharedSecret, publicKeyEphem, nil |
|
} |
|
|
|
// x25519Decap uses the receiver's secret key |secretKeyR| to recover the |
|
// ephemeral symmetric key contained in |enc|. |
|
func x25519Decap(enc, secretKeyR []byte) ([]byte, error) { |
|
dh, err := curve25519.X25519(secretKeyR, enc) |
|
if err != nil { |
|
return nil, err |
|
} |
|
// For simplicity, we recompute the receiver's public key. A production |
|
// implementation of HPKE should incorporate it into the receiver key |
|
// and halve the number of point multiplications needed. |
|
publicKeyR, err := curve25519.X25519(secretKeyR, curve25519.Basepoint) |
|
if err != nil { |
|
return nil, err |
|
} |
|
return extractAndExpand(dh, enc, publicKeyR[:]), nil |
|
} |
|
|
|
func extractAndExpand(dh, enc, publicKeyR []byte) []byte { |
|
var kemContext []byte |
|
kemContext = append(kemContext, enc...) |
|
kemContext = append(kemContext, publicKeyR...) |
|
|
|
suite := []byte("KEM") |
|
suite = appendBigEndianUint16(suite, X25519WithHKDFSHA256) |
|
|
|
kdfHash := getKDFHash(HKDFSHA256) |
|
prk := labeledExtract(kdfHash, nil, suite, []byte("eae_prk"), dh) |
|
return labeledExpand(kdfHash, prk, suite, []byte("shared_secret"), kemContext, 32) |
|
}
|
|
|