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.

340 lines
8.9 KiB

  1. // Uses nacl's secret_box to encrypt a net.Conn.
  2. // It is (meant to be) an implementation of the STS protocol.
  3. // See docs/sts-final.pdf for more info
  4. package p2p
  5. import (
  6. "bytes"
  7. crand "crypto/rand"
  8. "crypto/sha256"
  9. "encoding/binary"
  10. "errors"
  11. "io"
  12. "net"
  13. "sync"
  14. "time"
  15. "github.com/tendermint/tendermint/Godeps/_workspace/src/golang.org/x/crypto/nacl/box"
  16. "github.com/tendermint/tendermint/Godeps/_workspace/src/golang.org/x/crypto/nacl/secretbox"
  17. "github.com/tendermint/tendermint/Godeps/_workspace/src/golang.org/x/crypto/ripemd160"
  18. acm "github.com/tendermint/tendermint/account"
  19. bm "github.com/tendermint/tendermint/binary"
  20. . "github.com/tendermint/tendermint/common"
  21. )
  22. // 2 + 1024 == 1026 total frame size
  23. const dataLenSize = 2 // uint16 to describe the length, is <= dataMaxSize
  24. const dataMaxSize = 1024
  25. const totalFrameSize = dataMaxSize + dataLenSize
  26. const sealedFrameSize = totalFrameSize + secretbox.Overhead
  27. // Implements net.Conn
  28. type SecretConnection struct {
  29. conn io.ReadWriteCloser
  30. recvBuffer []byte
  31. recvNonce *[24]byte
  32. sendNonce *[24]byte
  33. remPubKey acm.PubKeyEd25519
  34. shrSecret *[32]byte // shared secret
  35. }
  36. // Performs handshake and returns a new authenticated SecretConnection.
  37. // Returns nil if error in handshake.
  38. // Caller should call conn.Close()
  39. // See docs/sts-final.pdf for more information.
  40. func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey acm.PrivKeyEd25519) (*SecretConnection, error) {
  41. locPubKey := locPrivKey.PubKey().(acm.PubKeyEd25519)
  42. // Generate ephemeral keys for perfect forward secrecy.
  43. locEphPub, locEphPriv := genEphKeys()
  44. // Write local ephemeral pubkey and receive one too.
  45. remEphPub, err := shareEphPubKey(conn, locEphPub)
  46. // Compute common shared secret.
  47. shrSecret := computeSharedSecret(remEphPub, locEphPriv)
  48. // Sort by lexical order.
  49. loEphPub, hiEphPub := sort32(locEphPub, remEphPub)
  50. // Generate nonces to use for secretbox.
  51. recvNonce, sendNonce := genNonces(loEphPub, hiEphPub, locEphPub == loEphPub)
  52. // Generate common challenge to sign.
  53. challenge := genChallenge(loEphPub, hiEphPub)
  54. // Construct SecretConnection.
  55. sc := &SecretConnection{
  56. conn: conn,
  57. recvBuffer: nil,
  58. recvNonce: recvNonce,
  59. sendNonce: sendNonce,
  60. remPubKey: nil,
  61. shrSecret: shrSecret,
  62. }
  63. // Sign the challenge bytes for authentication.
  64. locSignature := signChallenge(challenge, locPrivKey)
  65. // Share (in secret) each other's pubkey & challenge signature
  66. remPubKey, remSignature, err := shareAuthSignature(sc, locPubKey, locSignature)
  67. if err != nil {
  68. return nil, err
  69. }
  70. if !remPubKey.VerifyBytes(challenge[:], remSignature) {
  71. return nil, errors.New("Challenge verification failed")
  72. }
  73. // We've authorized.
  74. sc.remPubKey = remPubKey
  75. return sc, nil
  76. }
  77. // Returns authenticated remote pubkey
  78. func (sc *SecretConnection) RemotePubKey() acm.PubKeyEd25519 {
  79. return sc.remPubKey
  80. }
  81. // Writes encrypted frames of `sealedFrameSize`
  82. // CONTRACT: data smaller than dataMaxSize is read atomically.
  83. func (sc *SecretConnection) Write(data []byte) (n int, err error) {
  84. for 0 < len(data) {
  85. var frame []byte = make([]byte, totalFrameSize)
  86. var chunk []byte
  87. if dataMaxSize < len(data) {
  88. chunk = data[:dataMaxSize]
  89. data = data[dataMaxSize:]
  90. } else {
  91. chunk = data
  92. data = nil
  93. }
  94. chunkLength := len(chunk)
  95. binary.BigEndian.PutUint16(frame, uint16(chunkLength))
  96. copy(frame[dataLenSize:], chunk)
  97. // encrypt the frame
  98. var sealedFrame = make([]byte, sealedFrameSize)
  99. secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret)
  100. // fmt.Printf("secretbox.Seal(sealed:%X,sendNonce:%X,shrSecret:%X\n", sealedFrame, sc.sendNonce, sc.shrSecret)
  101. incr2Nonce(sc.sendNonce)
  102. // end encryption
  103. _, err := sc.conn.Write(sealedFrame)
  104. if err != nil {
  105. return n, err
  106. } else {
  107. n += len(chunk)
  108. }
  109. }
  110. return
  111. }
  112. // CONTRACT: data smaller than dataMaxSize is read atomically.
  113. func (sc *SecretConnection) Read(data []byte) (n int, err error) {
  114. if 0 < len(sc.recvBuffer) {
  115. n_ := copy(data, sc.recvBuffer)
  116. sc.recvBuffer = sc.recvBuffer[n_:]
  117. return
  118. }
  119. sealedFrame := make([]byte, sealedFrameSize)
  120. _, err = io.ReadFull(sc.conn, sealedFrame)
  121. if err != nil {
  122. return
  123. }
  124. // decrypt the frame
  125. var frame = make([]byte, totalFrameSize)
  126. // fmt.Printf("secretbox.Open(sealed:%X,recvNonce:%X,shrSecret:%X\n", sealedFrame, sc.recvNonce, sc.shrSecret)
  127. _, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret)
  128. if !ok {
  129. return n, errors.New("Failed to decrypt SecretConnection")
  130. }
  131. incr2Nonce(sc.recvNonce)
  132. // end decryption
  133. var chunkLength = binary.BigEndian.Uint16(frame)
  134. var chunk = frame[dataLenSize : dataLenSize+chunkLength]
  135. n = copy(data, chunk)
  136. sc.recvBuffer = chunk[n:]
  137. return
  138. }
  139. // Implements net.Conn
  140. func (sc *SecretConnection) Close() error { return sc.conn.Close() }
  141. func (sc *SecretConnection) LocalAddr() net.Addr { return sc.conn.(net.Conn).LocalAddr() }
  142. func (sc *SecretConnection) RemoteAddr() net.Addr { return sc.conn.(net.Conn).RemoteAddr() }
  143. func (sc *SecretConnection) SetDeadline(t time.Time) error { return sc.conn.(net.Conn).SetDeadline(t) }
  144. func (sc *SecretConnection) SetReadDeadline(t time.Time) error {
  145. return sc.conn.(net.Conn).SetReadDeadline(t)
  146. }
  147. func (sc *SecretConnection) SetWriteDeadline(t time.Time) error {
  148. return sc.conn.(net.Conn).SetWriteDeadline(t)
  149. }
  150. func genEphKeys() (ephPub, ephPriv *[32]byte) {
  151. var err error
  152. ephPub, ephPriv, err = box.GenerateKey(crand.Reader)
  153. if err != nil {
  154. panic("Could not generate ephemeral keypairs")
  155. }
  156. return
  157. }
  158. func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[32]byte, err error) {
  159. var err1, err2 error
  160. var wg sync.WaitGroup
  161. wg.Add(2)
  162. go func() {
  163. defer wg.Done()
  164. _, err1 = conn.Write(locEphPub[:])
  165. }()
  166. go func() {
  167. defer wg.Done()
  168. remEphPub = new([32]byte)
  169. _, err2 = io.ReadFull(conn, remEphPub[:])
  170. }()
  171. wg.Wait()
  172. if err1 != nil {
  173. return nil, err1
  174. }
  175. if err2 != nil {
  176. return nil, err2
  177. }
  178. return remEphPub, nil
  179. }
  180. func computeSharedSecret(remPubKey, locPrivKey *[32]byte) (shrSecret *[32]byte) {
  181. shrSecret = new([32]byte)
  182. box.Precompute(shrSecret, remPubKey, locPrivKey)
  183. return
  184. }
  185. func sort32(foo, bar *[32]byte) (lo, hi *[32]byte) {
  186. if bytes.Compare(foo[:], bar[:]) < 0 {
  187. lo = foo
  188. hi = bar
  189. } else {
  190. lo = bar
  191. hi = foo
  192. }
  193. return
  194. }
  195. func genNonces(loPubKey, hiPubKey *[32]byte, locIsLo bool) (recvNonce, sendNonce *[24]byte) {
  196. nonce1 := hash24(append(loPubKey[:], hiPubKey[:]...))
  197. nonce2 := new([24]byte)
  198. copy(nonce2[:], nonce1[:])
  199. nonce2[len(nonce2)-1] ^= 0x01
  200. if locIsLo {
  201. recvNonce = nonce1
  202. sendNonce = nonce2
  203. } else {
  204. recvNonce = nonce2
  205. sendNonce = nonce1
  206. }
  207. return
  208. }
  209. func genChallenge(loPubKey, hiPubKey *[32]byte) (challenge *[32]byte) {
  210. return hash32(append(loPubKey[:], hiPubKey[:]...))
  211. }
  212. func signChallenge(challenge *[32]byte, locPrivKey acm.PrivKeyEd25519) (signature acm.SignatureEd25519) {
  213. signature = locPrivKey.Sign(challenge[:]).(acm.SignatureEd25519)
  214. return
  215. }
  216. type authSigMessage struct {
  217. Key acm.PubKeyEd25519
  218. Sig acm.SignatureEd25519
  219. }
  220. func shareAuthSignature(sc *SecretConnection, pubKey acm.PubKeyEd25519, signature acm.SignatureEd25519) (acm.PubKeyEd25519, acm.SignatureEd25519, error) {
  221. var recvMsg authSigMessage
  222. var err1, err2 error
  223. Parallel(
  224. func() {
  225. msgBytes := bm.BinaryBytes(authSigMessage{pubKey, signature})
  226. _, err1 = sc.Write(msgBytes)
  227. },
  228. func() {
  229. // NOTE relies on atomicity of small data.
  230. readBuffer := make([]byte, dataMaxSize)
  231. _, err2 = sc.Read(readBuffer)
  232. if err2 != nil {
  233. return
  234. }
  235. n := int64(0) // not used.
  236. recvMsg = bm.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), &n, &err2).(authSigMessage)
  237. })
  238. if err1 != nil {
  239. return nil, nil, err1
  240. }
  241. if err2 != nil {
  242. return nil, nil, err2
  243. }
  244. return recvMsg.Key, recvMsg.Sig, nil
  245. }
  246. func verifyChallengeSignature(challenge *[32]byte, remPubKey acm.PubKeyEd25519, remSignature acm.SignatureEd25519) bool {
  247. return remPubKey.VerifyBytes(challenge[:], remSignature)
  248. }
  249. //--------------------------------------------------------------------------------
  250. // sha256
  251. func hash32(input []byte) (res *[32]byte) {
  252. hasher := sha256.New()
  253. hasher.Write(input) // does not error
  254. resSlice := hasher.Sum(nil)
  255. res = new([32]byte)
  256. copy(res[:], resSlice)
  257. return
  258. }
  259. // We only fill in the first 20 bytes with ripemd160
  260. func hash24(input []byte) (res *[24]byte) {
  261. hasher := ripemd160.New()
  262. hasher.Write(input) // does not error
  263. resSlice := hasher.Sum(nil)
  264. res = new([24]byte)
  265. copy(res[:], resSlice)
  266. return
  267. }
  268. // ripemd160
  269. func hash20(input []byte) (res *[20]byte) {
  270. hasher := ripemd160.New()
  271. hasher.Write(input) // does not error
  272. resSlice := hasher.Sum(nil)
  273. res = new([20]byte)
  274. copy(res[:], resSlice)
  275. return
  276. }
  277. // increment nonce big-endian by 2 with wraparound.
  278. func incr2Nonce(nonce *[24]byte) {
  279. incrNonce(nonce)
  280. incrNonce(nonce)
  281. }
  282. // increment nonce big-endian by 1 with wraparound.
  283. func incrNonce(nonce *[24]byte) {
  284. for i := 23; 0 <= i; i-- {
  285. nonce[i] += 1
  286. if nonce[i] != 0 {
  287. return
  288. }
  289. }
  290. }