120 lines
2.4 KiB
Go
120 lines
2.4 KiB
Go
package secio
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/hmac"
|
|
"crypto/sha1"
|
|
"crypto/sha512"
|
|
"hash"
|
|
|
|
ci "github.com/libp2p/go-libp2p-core/crypto"
|
|
sha256 "github.com/minio/sha256-simd"
|
|
)
|
|
|
|
// SupportedExchanges is the list of supported ECDH curves
|
|
var SupportedExchanges = DefaultSupportedExchanges
|
|
|
|
const DefaultSupportedExchanges = "P-256,P-384,P-521"
|
|
|
|
// SupportedCiphers is the list of supported Ciphers
|
|
var SupportedCiphers = DefaultSupportedCiphers
|
|
|
|
const DefaultSupportedCiphers = "AES-256,AES-128"
|
|
|
|
// SupportedHashes is the list of supported Hashes
|
|
var SupportedHashes = DefaultSupportedHashes
|
|
|
|
const DefaultSupportedHashes = "SHA256,SHA512"
|
|
|
|
// HMAC carries a hash and its size
|
|
type HMAC struct {
|
|
hash.Hash
|
|
size int
|
|
}
|
|
|
|
// encParams represent encryption parameters
|
|
type encParams struct {
|
|
// keys
|
|
permanentPubKey ci.PubKey
|
|
ephemeralPubKey []byte
|
|
keys ci.StretchedKeys
|
|
|
|
// selections
|
|
curveT string
|
|
cipherT string
|
|
hashT string
|
|
|
|
// cipher + mac
|
|
cipher cipher.Stream
|
|
mac HMAC
|
|
}
|
|
|
|
func (e *encParams) makeMacAndCipher() error {
|
|
m, err := newMac(e.hashT, e.keys.MacKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bc, err := newBlockCipher(e.cipherT, e.keys.CipherKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
e.cipher = cipher.NewCTR(bc, e.keys.IV)
|
|
e.mac = m
|
|
return nil
|
|
}
|
|
|
|
func newMac(hashType string, key []byte) (HMAC, error) {
|
|
switch hashType {
|
|
case "SHA1":
|
|
return HMAC{hmac.New(sha1.New, key), sha1.Size}, nil
|
|
case "SHA512":
|
|
return HMAC{hmac.New(sha512.New, key), sha512.Size}, nil
|
|
case "SHA256":
|
|
return HMAC{hmac.New(sha256.New, key), sha256.Size}, nil
|
|
default:
|
|
return HMAC{}, fmt.Errorf("Unrecognized hash type: %s", hashType)
|
|
}
|
|
}
|
|
|
|
func newBlockCipher(cipherT string, key []byte) (cipher.Block, error) {
|
|
switch cipherT {
|
|
case "AES-128", "AES-256":
|
|
return aes.NewCipher(key)
|
|
default:
|
|
return nil, fmt.Errorf("Unrecognized cipher type: %s", cipherT)
|
|
}
|
|
}
|
|
|
|
// Determines which algorithm to use. Note: f(a, b) = f(b, a)
|
|
func selectBest(order int, p1, p2 string) (string, error) {
|
|
var f, s []string
|
|
switch {
|
|
case order < 0:
|
|
f = strings.Split(p2, ",")
|
|
s = strings.Split(p1, ",")
|
|
case order > 0:
|
|
f = strings.Split(p1, ",")
|
|
s = strings.Split(p2, ",")
|
|
default: // Exact same preferences.
|
|
p := strings.Split(p1, ",")
|
|
return p[0], nil
|
|
}
|
|
|
|
for _, fc := range f {
|
|
for _, sc := range s {
|
|
if fc == sc {
|
|
return fc, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return "", errors.New("No algorithms in common!")
|
|
}
|