uniformdh.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright (c) 2014, Yawning Angel <yawning at schwanenlied dot me>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. *
  11. * * Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  19. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. * POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. // Package uniformdh implements the Tor Project's UniformDH key exchange
  28. // mechanism as defined in the obfs3 protocol specification. This
  29. // implementation is suitable for obfuscation but MUST NOT BE USED when strong
  30. // security is required as it is not constant time.
  31. package uniformdh // import "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/uniformdh"
  32. import (
  33. "fmt"
  34. "io"
  35. "math/big"
  36. )
  37. const (
  38. // Size is the size of a UniformDH key or shared secret in bytes.
  39. Size = 1536 / 8
  40. // modpStr is the RFC3526 1536-bit MODP Group (Group 5).
  41. modpStr = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
  42. "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
  43. "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
  44. "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
  45. "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
  46. "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
  47. "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
  48. "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
  49. g = 2
  50. )
  51. var modpGroup *big.Int
  52. var gen *big.Int
  53. // A PrivateKey represents a UniformDH private key.
  54. type PrivateKey struct {
  55. PublicKey
  56. privateKey *big.Int
  57. }
  58. // A PublicKey represents a UniformDH public key.
  59. type PublicKey struct {
  60. bytes []byte
  61. publicKey *big.Int
  62. }
  63. // Bytes returns the byte representation of a PublicKey.
  64. func (pub *PublicKey) Bytes() (pubBytes []byte, err error) {
  65. if len(pub.bytes) != Size || pub.bytes == nil {
  66. return nil, fmt.Errorf("public key is not initialized")
  67. }
  68. pubBytes = make([]byte, Size)
  69. copy(pubBytes, pub.bytes)
  70. return
  71. }
  72. // SetBytes sets the PublicKey from a byte slice.
  73. func (pub *PublicKey) SetBytes(pubBytes []byte) error {
  74. if len(pubBytes) != Size {
  75. return fmt.Errorf("public key length %d is not %d", len(pubBytes), Size)
  76. }
  77. pub.bytes = make([]byte, Size)
  78. copy(pub.bytes, pubBytes)
  79. pub.publicKey = new(big.Int).SetBytes(pub.bytes)
  80. return nil
  81. }
  82. // GenerateKey generates a UniformDH keypair using the random source random.
  83. func GenerateKey(random io.Reader) (priv *PrivateKey, err error) {
  84. privBytes := make([]byte, Size)
  85. if _, err = io.ReadFull(random, privBytes); err != nil {
  86. return
  87. }
  88. priv, err = generateKey(privBytes)
  89. return
  90. }
  91. func generateKey(privBytes []byte) (priv *PrivateKey, err error) {
  92. // This function does all of the actual heavy lifting of creating a public
  93. // key from a raw 192 byte private key. It is split so that the KAT tests
  94. // can be written easily, and not exposed since non-ephemeral keys are a
  95. // terrible idea.
  96. if len(privBytes) != Size {
  97. return nil, fmt.Errorf("invalid private key size %d", len(privBytes))
  98. }
  99. // To pick a private UniformDH key, we pick a random 1536-bit number,
  100. // and make it even by setting its low bit to 0
  101. privBn := new(big.Int).SetBytes(privBytes)
  102. wasEven := privBn.Bit(0) == 0
  103. privBn = privBn.SetBit(privBn, 0, 0)
  104. // Let x be that private key, and X = g^x (mod p).
  105. pubBn := new(big.Int).Exp(gen, privBn, modpGroup)
  106. pubAlt := new(big.Int).Sub(modpGroup, pubBn)
  107. // When someone sends her public key to the other party, she randomly
  108. // decides whether to send X or p-X. Use the lowest most bit of the
  109. // private key here as the random coin flip since it is masked out and not
  110. // used.
  111. //
  112. // Note: The spec doesn't explicitly specify it, but here we prepend zeros
  113. // to the key so that it is always exactly Size bytes.
  114. pubBytes := make([]byte, Size)
  115. if wasEven {
  116. err = prependZeroBytes(pubBytes, pubBn.Bytes())
  117. } else {
  118. err = prependZeroBytes(pubBytes, pubAlt.Bytes())
  119. }
  120. if err != nil {
  121. return
  122. }
  123. priv = new(PrivateKey)
  124. priv.PublicKey.bytes = pubBytes
  125. priv.PublicKey.publicKey = pubBn
  126. priv.privateKey = privBn
  127. return
  128. }
  129. // Handshake generates a shared secret given a PrivateKey and PublicKey.
  130. func Handshake(privateKey *PrivateKey, publicKey *PublicKey) (sharedSecret []byte, err error) {
  131. // When a party wants to calculate the shared secret, she raises the
  132. // foreign public key to her private key.
  133. secretBn := new(big.Int).Exp(publicKey.publicKey, privateKey.privateKey, modpGroup)
  134. sharedSecret = make([]byte, Size)
  135. err = prependZeroBytes(sharedSecret, secretBn.Bytes())
  136. return
  137. }
  138. func prependZeroBytes(dst, src []byte) error {
  139. zeros := len(dst) - len(src)
  140. if zeros < 0 {
  141. return fmt.Errorf("src length is greater than destination: %d", zeros)
  142. }
  143. for i := 0; i < zeros; i++ {
  144. dst[i] = 0
  145. }
  146. copy(dst[zeros:], src)
  147. return nil
  148. }
  149. func init() {
  150. // Load the MODP group and the generator.
  151. var ok bool
  152. modpGroup, ok = new(big.Int).SetString(modpStr, 16)
  153. if !ok {
  154. panic("Failed to load the RFC3526 MODP Group")
  155. }
  156. gen = big.NewInt(g)
  157. }