More protocols
This commit is contained in:
141
protocol/meshcore/crypto/x25519.go
Normal file
141
protocol/meshcore/crypto/x25519.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
type SharedSecret struct {
|
||||
aBytes [32]byte
|
||||
}
|
||||
|
||||
func MakeSharedSecret(key []byte) SharedSecret {
|
||||
var secret SharedSecret
|
||||
copy(secret.aBytes[:], key)
|
||||
return secret
|
||||
}
|
||||
|
||||
func MakeSharedSecretFromGroupSecret(group []byte) SharedSecret {
|
||||
var secret SharedSecret
|
||||
copy(secret.aBytes[:16], group)
|
||||
return secret
|
||||
}
|
||||
|
||||
func (ss *SharedSecret) HMAC(message []byte) uint16 {
|
||||
h := hmac.New(sha256.New, ss.aBytes[:])
|
||||
h.Write(message)
|
||||
r := h.Sum(nil)
|
||||
return binary.BigEndian.Uint16(r[:2])
|
||||
}
|
||||
|
||||
func (ss *SharedSecret) key() []byte {
|
||||
return ss.aBytes[:aes.BlockSize]
|
||||
}
|
||||
|
||||
func (ss *SharedSecret) Decrypt(text []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(ss.key())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
length := len(text)
|
||||
message := make([]byte, length)
|
||||
copy(message, text)
|
||||
|
||||
const chunkSize = aes.BlockSize
|
||||
remain := length % chunkSize
|
||||
|
||||
if remain > 0 {
|
||||
padding := chunkSize - remain
|
||||
message = append(message, make([]byte, padding)...)
|
||||
}
|
||||
|
||||
for i, l := 0, len(message); i < l; i += chunkSize {
|
||||
block.Decrypt(message[i:i+chunkSize], message[i:i+chunkSize])
|
||||
}
|
||||
|
||||
return message[:length], nil
|
||||
}
|
||||
|
||||
func (ss *SharedSecret) MACThenDecrypt(text []byte, mac uint16) ([]byte, error) {
|
||||
if our := ss.HMAC(text); our != mac {
|
||||
return nil, fmt.Errorf("expected MAC %04X, got %04X", mac, our)
|
||||
}
|
||||
return ss.Decrypt(text)
|
||||
}
|
||||
|
||||
func (ss *SharedSecret) Encrypt(message []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(ss.key())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
text := make([]byte, len(message))
|
||||
copy(text, message)
|
||||
|
||||
const chunkSize = aes.BlockSize
|
||||
remain := len(text) % chunkSize
|
||||
|
||||
if remain > 0 {
|
||||
padding := chunkSize - remain
|
||||
text = append(text, make([]byte, padding)...)
|
||||
}
|
||||
|
||||
for i, l := 0, len(text); i < l; i += chunkSize {
|
||||
block.Encrypt(text[i:i+chunkSize], text[i:i+chunkSize])
|
||||
}
|
||||
|
||||
return text, nil
|
||||
}
|
||||
|
||||
func (ss *SharedSecret) EncryptThenMAC(message []byte) (uint16, []byte, error) {
|
||||
text, err := ss.Encrypt(message)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return ss.HMAC(text), text, nil
|
||||
}
|
||||
|
||||
type StaticSecret [32]byte
|
||||
|
||||
func (ss StaticSecret) PublicKey() (*PublicKey, error) {
|
||||
pub, err := curve25519.X25519(ss[:], curve25519.Basepoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewPublicKey(pub)
|
||||
}
|
||||
|
||||
func (ss StaticSecret) DiffieHellman(other *PublicKey) (SharedSecret, error) {
|
||||
shared, err := curve25519.X25519(ss[:], other.Bytes())
|
||||
if err != nil {
|
||||
return SharedSecret{}, err
|
||||
}
|
||||
|
||||
var montgomery SharedSecret
|
||||
copy(montgomery.aBytes[:], shared)
|
||||
return montgomery, nil
|
||||
}
|
||||
|
||||
type Signature [64]byte
|
||||
|
||||
func (sig Signature) MarshalJSON() ([]byte, error) {
|
||||
s := hex.EncodeToString(sig[:])
|
||||
return json.Marshal(s)
|
||||
}
|
||||
|
||||
func (sig *Signature) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
copy((*sig)[:], []byte(s))
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user