113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
package common
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
crand "crypto/rand"
|
|
"errors"
|
|
"fmt"
|
|
mrand "math/rand"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
)
|
|
|
|
// IsPubKeyEqual checks that two public keys are equal
|
|
func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool {
|
|
if !ValidatePublicKey(a) {
|
|
return false
|
|
} else if !ValidatePublicKey(b) {
|
|
return false
|
|
}
|
|
// the curve is always the same, just compare the points
|
|
return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0
|
|
}
|
|
|
|
// ValidatePublicKey checks the format of the given public key.
|
|
func ValidatePublicKey(k *ecdsa.PublicKey) bool {
|
|
return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0
|
|
}
|
|
|
|
// BytesToUintLittleEndian converts the slice to 64-bit unsigned integer.
|
|
func BytesToUintLittleEndian(b []byte) (res uint64) {
|
|
mul := uint64(1)
|
|
for i := 0; i < len(b); i++ {
|
|
res += uint64(b[i]) * mul
|
|
mul *= 256
|
|
}
|
|
return res
|
|
}
|
|
|
|
// BytesToUintBigEndian converts the slice to 64-bit unsigned integer.
|
|
func BytesToUintBigEndian(b []byte) (res uint64) {
|
|
for i := 0; i < len(b); i++ {
|
|
res *= 256
|
|
res += uint64(b[i])
|
|
}
|
|
return res
|
|
}
|
|
|
|
// ContainsOnlyZeros checks if the data contain only zeros.
|
|
func ContainsOnlyZeros(data []byte) bool {
|
|
for _, b := range data {
|
|
if b != 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// GenerateSecureRandomData generates random data where extra security is required.
|
|
// The purpose of this function is to prevent some bugs in software or in hardware
|
|
// from delivering not-very-random data. This is especially useful for AES nonce,
|
|
// where true randomness does not really matter, but it is very important to have
|
|
// a unique nonce for every message.
|
|
func GenerateSecureRandomData(length int) ([]byte, error) {
|
|
x := make([]byte, length)
|
|
y := make([]byte, length)
|
|
res := make([]byte, length)
|
|
|
|
_, err := crand.Read(x)
|
|
if err != nil {
|
|
return nil, err
|
|
} else if !ValidateDataIntegrity(x, length) {
|
|
return nil, errors.New("crypto/rand failed to generate secure random data")
|
|
}
|
|
_, err = mrand.Read(y) // nolint: gosec
|
|
if err != nil {
|
|
return nil, err
|
|
} else if !ValidateDataIntegrity(y, length) {
|
|
return nil, errors.New("math/rand failed to generate secure random data")
|
|
}
|
|
for i := 0; i < length; i++ {
|
|
res[i] = x[i] ^ y[i]
|
|
}
|
|
if !ValidateDataIntegrity(res, length) {
|
|
return nil, errors.New("failed to generate secure random data")
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
// GenerateRandomID generates a random string, which is then returned to be used as a key id
|
|
func GenerateRandomID() (id string, err error) {
|
|
buf, err := GenerateSecureRandomData(KeyIDSize)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if !ValidateDataIntegrity(buf, KeyIDSize) {
|
|
return "", fmt.Errorf("error in generateRandomID: crypto/rand failed to generate random data")
|
|
}
|
|
id = common.Bytes2Hex(buf)
|
|
return id, err
|
|
}
|
|
|
|
// ValidateDataIntegrity returns false if the data have the wrong or contains all zeros,
|
|
// which is the simplest and the most common bug.
|
|
func ValidateDataIntegrity(k []byte, expectedSize int) bool {
|
|
if len(k) != expectedSize {
|
|
return false
|
|
}
|
|
if expectedSize > 3 && ContainsOnlyZeros(k) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|