Commit c6823ac6 authored by Brendan Mc's avatar Brendan Mc

Cleaned up code some.

parent 80ec51f1
package crypto
import (
"bytes"
"errors"
"crypto/elliptic"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"hash"
"math/big"
"code.google.com/p/goprotobuf/proto"
)
......@@ -19,9 +27,6 @@ type PrivKey interface {
// Cryptographically sign the given bytes
Sign([]byte) ([]byte, error)
// Decrypt a message encrypted with this keys public key
Decrypt([]byte) ([]byte, error)
// Return a public key paired with this private key
GetPublic() PubKey
......@@ -36,13 +41,13 @@ type PubKey interface {
// Verify that 'sig' is the signed hash of 'data'
Verify(data []byte, sig []byte) (bool, error)
// Encrypt the given data with the public key
Encrypt([]byte) ([]byte, error)
// Bytes returns a serialized, storeable representation of this key
Bytes() ([]byte, error)
}
// Given a public key, generates the shared key.
type GenSharedKey func([]byte) ([]byte, error)
func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
switch typ {
case RSA:
......@@ -57,6 +62,144 @@ func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
}
}
// Generates an ephemeral public key and returns a function that will compute
// the shared secret key. Used in the identify module.
//
// Focuses only on ECDH now, but can be made more general in the future.
func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) {
var curve elliptic.Curve
switch curveName {
case "P-224":
curve = elliptic.P224()
case "P-256":
curve = elliptic.P256()
case "P-384":
curve = elliptic.P384()
case "P-521":
curve = elliptic.P521()
}
priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, nil, err
}
var pubKey bytes.Buffer
pubKey.Write(x.Bytes())
pubKey.Write(y.Bytes())
done := func(theirPub []byte) ([]byte, error) {
// Verify and unpack node's public key.
curveSize := curve.Params().BitSize
if len(theirPub) != (curveSize / 4) {
return nil, errors.New("Malformed public key.")
}
bound := (curveSize / 8)
x := big.NewInt(0)
y := big.NewInt(0)
x.SetBytes(theirPub[0:bound])
y.SetBytes(theirPub[bound : bound*2])
if !curve.IsOnCurve(x, y) {
return nil, errors.New("Invalid public key.")
}
// Generate shared secret.
secret, _ := curve.ScalarMult(x, y, priv)
return secret.Bytes(), nil
}
return pubKey.Bytes(), done, nil
}
// Generates a set of keys for each party by stretching the shared key.
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
func KeyStretcher(cmp int, cipherType string, hashType string, secret []byte) ([]byte, []byte, []byte, []byte, []byte, []byte) {
var cipherKeySize int
switch cipherType {
case "AES-128":
cipherKeySize = 16
case "AES-256":
cipherKeySize = 32
}
ivSize := 16
hmacKeySize := 20
seed := []byte("key expansion")
result := make([]byte, 2*(ivSize+cipherKeySize+hmacKeySize))
var h func() hash.Hash
switch hashType {
case "SHA1":
h = sha1.New
case "SHA256":
h = sha256.New
case "SHA512":
h = sha512.New
}
m := hmac.New(h, secret)
m.Write(seed)
a := m.Sum(nil)
j := 0
for j < len(result) {
m.Reset()
m.Write(a)
m.Write(seed)
b := m.Sum(nil)
todo := len(b)
if j+todo > len(result) {
todo = len(result) - j
}
copy(result[j:j+todo], b)
j += todo
m.Reset()
m.Write(a)
a = m.Sum(nil)
}
myResult := make([]byte, ivSize+cipherKeySize+hmacKeySize)
theirResult := make([]byte, ivSize+cipherKeySize+hmacKeySize)
half := len(result) / 2
if cmp == 1 {
copy(myResult, result[:half])
copy(theirResult, result[half:])
} else if cmp == -1 {
copy(myResult, result[half:])
copy(theirResult, result[:half])
} else { // Shouldn't happen, but oh well.
copy(myResult, result[half:])
copy(theirResult, result[half:])
}
myIV := myResult[0:ivSize]
myCKey := myResult[ivSize : ivSize+cipherKeySize]
myMKey := myResult[ivSize+cipherKeySize:]
theirIV := theirResult[0:ivSize]
theirCKey := theirResult[ivSize : ivSize+cipherKeySize]
theirMKey := theirResult[ivSize+cipherKeySize:]
return myIV, theirIV, myCKey, theirCKey, myMKey, theirMKey
}
func UnmarshalPublicKey(data []byte) (PubKey, error) {
pmes := new(PBPublicKey)
err := proto.Unmarshal(data, pmes)
......
......@@ -28,10 +28,6 @@ func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) {
return true, nil
}
func (pk *RsaPublicKey) Encrypt(message []byte) ([]byte, error) {
return rsa.EncryptPKCS1v15(rand.Reader, pk.k, message)
}
func (pk *RsaPublicKey) Bytes() ([]byte, error) {
b, err := x509.MarshalPKIXPublicKey(pk.k)
if err != nil {
......@@ -56,10 +52,6 @@ func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
return rsa.SignPKCS1v15(rand.Reader, sk.k, crypto.SHA256, hashed[:])
}
func (sk *RsaPrivateKey) Decrypt(ciphertext []byte) ([]byte, error) {
return rsa.DecryptPKCS1v15(rand.Reader, sk.k, ciphertext)
}
func (sk *RsaPrivateKey) GetPublic() PubKey {
return &RsaPublicKey{&sk.k.PublicKey}
}
......
......@@ -4,18 +4,17 @@ package identify
import (
"bytes"
"errors"
"strings"
"crypto/aes"
"crypto/cipher"
"crypto/elliptic"
"crypto/hmac"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"errors"
"hash"
"math/big"
"strings"
proto "code.google.com/p/goprotobuf/proto"
ci "github.com/jbenet/go-ipfs/crypto"
......@@ -95,7 +94,7 @@ func Handshake(self, remote *peer.Peer, in, out chan []byte) (chan []byte, chan
return nil, nil, err
}
epubkey, done, err := generateEPubKey(exchange) // Generate EphemeralPubKey
epubkey, done, err := ci.GenerateEKeyPair(exchange) // Generate EphemeralPubKey
var handshake bytes.Buffer // Gather corpus to sign.
handshake.Write(encoded)
......@@ -144,87 +143,13 @@ func Handshake(self, remote *peer.Peer, in, out chan []byte) (chan []byte, chan
}
cmp := bytes.Compare(myPubKey, helloResp.GetPubkey())
mIV, tIV, mCKey, tCKey, mMKey, tMKey := keyGenerator(cmp, cipherType, hashType, secret)
mIV, tIV, mCKey, tCKey, mMKey, tMKey := ci.KeyStretcher(cmp, cipherType, hashType, secret)
secureIn := make(chan []byte)
secureOut := make(chan []byte)
go func() {
myBlock, _ := aes.NewCipher(mCKey)
myCipher := cipher.NewCTR(myBlock, mIV)
theirBlock, _ := aes.NewCipher(tCKey)
theirCipher := cipher.NewCTR(theirBlock, tIV)
var myMac, theirMac hash.Hash
var macSize int
switch hashType {
case "SHA1":
myMac = hmac.New(sha1.New, mMKey)
theirMac = hmac.New(sha1.New, tMKey)
macSize = 20
case "SHA256":
myMac = hmac.New(sha256.New, mMKey)
theirMac = hmac.New(sha256.New, tMKey)
macSize = 32
case "SHA512":
myMac = hmac.New(sha512.New, mMKey)
theirMac = hmac.New(sha512.New, tMKey)
macSize = 64
}
for {
select {
case data, ok := <-secureOut:
if !ok {
return
}
if len(data) == 0 {
continue
}
buff := make([]byte, len(data)+macSize)
myCipher.XORKeyStream(buff, data)
myMac.Write(buff[0:len(data)])
copy(buff[len(data):], myMac.Sum(nil))
myMac.Reset()
out <- buff
case data, ok := <-in:
if !ok {
return
}
if len(data) <= macSize {
continue
}
mark := len(data) - macSize
buff := make([]byte, mark)
theirCipher.XORKeyStream(buff, data[0:mark])
theirMac.Write(data[0:mark])
expected := theirMac.Sum(nil)
theirMac.Reset()
hmacOk := hmac.Equal(data[mark:], expected)
if hmacOk {
secureIn <- buff
} else {
secureIn <- nil
}
}
}
}()
go secureInProxy(in, secureIn, hashType, tIV, tCKey, tMKey)
go secureOutProxy(out, secureOut, hashType, mIV, mCKey, mMKey)
finished := []byte("Finished")
......@@ -240,99 +165,90 @@ func Handshake(self, remote *peer.Peer, in, out chan []byte) (chan []byte, chan
return secureIn, secureOut, nil
}
func IdFromPubKey(pk ci.PubKey) (peer.ID, error) {
b, err := pk.Bytes()
if err != nil {
return nil, err
}
hash, err := u.Hash(b)
if err != nil {
return nil, err
func makeMac(hashType string, key []byte) (hash.Hash, int) {
switch hashType {
case "SHA1":
return hmac.New(sha1.New, key), sha1.Size
case "SHA512":
return hmac.New(sha512.New, key), sha512.Size
default:
return hmac.New(sha256.New, key), sha256.Size
}
return peer.ID(hash), nil
}
// Generates a set of keys for each party by stretching the shared key.
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
func keyGenerator(cmp int, cipherType string, hashType string, secret []byte) ([]byte, []byte, []byte, []byte, []byte, []byte) {
var cipherKeySize int
switch cipherType {
case "AES-128":
cipherKeySize = 16
case "AES-256":
cipherKeySize = 32
}
ivSize := 16
hmacKeySize := 20
seed := []byte("key expansion")
func secureInProxy(in, secureIn chan []byte, hashType string, tIV, tCKey, tMKey []byte) {
theirBlock, _ := aes.NewCipher(tCKey)
theirCipher := cipher.NewCTR(theirBlock, tIV)
result := make([]byte, 2*(ivSize+cipherKeySize+hmacKeySize))
theirMac, macSize := makeMac(hashType, tMKey)
var h func() hash.Hash
for {
data, ok := <-in
if !ok {
return
}
switch hashType {
case "SHA1":
h = sha1.New
case "SHA256":
h = sha256.New
case "SHA512":
h = sha512.New
}
if len(data) <= macSize {
continue
}
m := hmac.New(h, secret)
m.Write(seed)
mark := len(data) - macSize
buff := make([]byte, mark)
a := m.Sum(nil)
theirCipher.XORKeyStream(buff, data[0:mark])
j := 0
for j < len(result) {
m.Reset()
m.Write(a)
m.Write(seed)
b := m.Sum(nil)
theirMac.Write(data[0:mark])
expected := theirMac.Sum(nil)
theirMac.Reset()
todo := len(b)
hmacOk := hmac.Equal(data[mark:], expected)
if j+todo > len(result) {
todo = len(result) - j
if hmacOk {
secureIn <- buff
} else {
secureIn <- nil
}
}
}
copy(result[j:j+todo], b)
func secureOutProxy(out, secureOut chan []byte, hashType string, mIV, mCKey, mMKey []byte) {
myBlock, _ := aes.NewCipher(mCKey)
myCipher := cipher.NewCTR(myBlock, mIV)
j += todo
myMac, macSize := makeMac(hashType, mMKey)
m.Reset()
m.Write(a)
a = m.Sum(nil)
}
for {
data, ok := <-secureOut
if !ok {
return
}
myResult := make([]byte, ivSize+cipherKeySize+hmacKeySize)
theirResult := make([]byte, ivSize+cipherKeySize+hmacKeySize)
if len(data) == 0 {
continue
}
half := len(result) / 2
buff := make([]byte, len(data)+macSize)
if cmp == 1 {
copy(myResult, result[:half])
copy(theirResult, result[half:])
} else if cmp == -1 {
copy(myResult, result[half:])
copy(theirResult, result[:half])
} else { // Shouldn't happen, but oh well.
copy(myResult, result[half:])
copy(theirResult, result[half:])
}
myCipher.XORKeyStream(buff, data)
myIV := myResult[0:ivSize]
myCKey := myResult[ivSize : ivSize+cipherKeySize]
myMKey := myResult[ivSize+cipherKeySize:]
myMac.Write(buff[0:len(data)])
copy(buff[len(data):], myMac.Sum(nil))
myMac.Reset()
theirIV := theirResult[0:ivSize]
theirCKey := theirResult[ivSize : ivSize+cipherKeySize]
theirMKey := theirResult[ivSize+cipherKeySize:]
out <- buff
}
}
return myIV, theirIV, myCKey, theirCKey, myMKey, theirMKey
func IdFromPubKey(pk ci.PubKey) (peer.ID, error) {
b, err := pk.Bytes()
if err != nil {
return nil, err
}
hash, err := u.Hash(b)
if err != nil {
return nil, err
}
return peer.ID(hash), nil
}
// Determines which algorithm to use. Note: f(a, b) = f(b, a)
......@@ -372,96 +288,3 @@ func selectBest(myPrefs, theirPrefs string) (string, error) {
return "", errors.New("No algorithms in common!")
}
// Generates an ephemeral public key and returns a function that will compute
// the shared secret key.
//
// Focuses only on ECDH now, but can be made more general in the future.
func generateEPubKey(exchange string) ([]byte, func([]byte) ([]byte, error), error) {
genKeyPair := func(curve elliptic.Curve) ([]byte, []byte, error) {
priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, nil, err
}
var pubKey bytes.Buffer
pubKey.Write(x.Bytes())
pubKey.Write(y.Bytes())
return pubKey.Bytes(), priv, nil
}
genSec := func(curve elliptic.Curve, theirPub []byte, myPriv []byte) ([]byte, error) {
// Verify and unpack node's public key.
curveSize := curve.Params().BitSize
if len(theirPub) != (curveSize / 4) {
return nil, errors.New("Malformed public key.")
}
bound := (curveSize / 8)
x := big.NewInt(0)
y := big.NewInt(0)
x.SetBytes(theirPub[0:bound])
y.SetBytes(theirPub[bound : bound*2])
if !curve.IsOnCurve(x, y) {
return nil, errors.New("Invalid public key.")
}
// Generate shared secret.
secret, _ := curve.ScalarMult(x, y, myPriv)
return secret.Bytes(), nil
}
switch exchange {
case "P-224":
curve := elliptic.P224()
pub, priv, err := genKeyPair(curve)
if err != nil {
return nil, nil, err
}
done := func(theirs []byte) ([]byte, error) { return genSec(curve, theirs, priv) }
return pub, done, nil
case "P-256":
curve := elliptic.P256()
pub, priv, err := genKeyPair(curve)
if err != nil {
return nil, nil, err
}
done := func(theirs []byte) ([]byte, error) { return genSec(curve, theirs, priv) }
return pub, done, nil
case "P-384":
curve := elliptic.P384()
pub, priv, err := genKeyPair(curve)
if err != nil {
return nil, nil, err
}
done := func(theirs []byte) ([]byte, error) { return genSec(curve, theirs, priv) }
return pub, done, nil
case "P-521":
curve := elliptic.P521()
pub, priv, err := genKeyPair(curve)
if err != nil {
return nil, nil, err
}
done := func(theirs []byte) ([]byte, error) { return genSec(curve, theirs, priv) }
return pub, done, nil
}
return nil, nil, errors.New("Something silly happened.")
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment