dh.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package codec
  2. import (
  3. "crypto/rand"
  4. "errors"
  5. "math/big"
  6. )
  7. // see https://www.zhihu.com/question/29383090/answer/70435297
  8. // see https://www.ietf.org/rfc/rfc3526.txt
  9. // 2048-bit MODP Group
  10. var (
  11. // ErrInvalidPriKey indicates the invalid private key.
  12. ErrInvalidPriKey = errors.New("invalid private key")
  13. // ErrInvalidPubKey indicates the invalid public key.
  14. ErrInvalidPubKey = errors.New("invalid public key")
  15. // ErrPubKeyOutOfBound indicates the public key is out of bound.
  16. ErrPubKeyOutOfBound = errors.New("public key out of bound")
  17. p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
  18. g, _ = new(big.Int).SetString("2", 16)
  19. zero = big.NewInt(0)
  20. )
  21. // DhKey defines the Diffie Hellman key.
  22. type DhKey struct {
  23. PriKey *big.Int
  24. PubKey *big.Int
  25. }
  26. // ComputeKey returns a key from public key and private key.
  27. func ComputeKey(pubKey, priKey *big.Int) (*big.Int, error) {
  28. if pubKey == nil {
  29. return nil, ErrInvalidPubKey
  30. }
  31. if pubKey.Sign() <= 0 && p.Cmp(pubKey) <= 0 {
  32. return nil, ErrPubKeyOutOfBound
  33. }
  34. if priKey == nil {
  35. return nil, ErrInvalidPriKey
  36. }
  37. return new(big.Int).Exp(pubKey, priKey, p), nil
  38. }
  39. // GenerateKey returns a Diffie Hellman key.
  40. func GenerateKey() (*DhKey, error) {
  41. var err error
  42. var x *big.Int
  43. for {
  44. x, err = rand.Int(rand.Reader, p)
  45. if err != nil {
  46. return nil, err
  47. }
  48. if zero.Cmp(x) < 0 {
  49. break
  50. }
  51. }
  52. key := new(DhKey)
  53. key.PriKey = x
  54. key.PubKey = new(big.Int).Exp(g, x, p)
  55. return key, nil
  56. }
  57. // NewPublicKey returns a public key from the given bytes.
  58. func NewPublicKey(bs []byte) *big.Int {
  59. return new(big.Int).SetBytes(bs)
  60. }
  61. // Bytes returns public key bytes.
  62. func (k *DhKey) Bytes() []byte {
  63. if k.PubKey == nil {
  64. return nil
  65. }
  66. byteLen := (p.BitLen() + 7) >> 3
  67. ret := make([]byte, byteLen)
  68. copyWithLeftPad(ret, k.PubKey.Bytes())
  69. return ret
  70. }
  71. func copyWithLeftPad(dst, src []byte) {
  72. padBytes := len(dst) - len(src)
  73. for i := 0; i < padBytes; i++ {
  74. dst[i] = 0
  75. }
  76. copy(dst[padBytes:], src)
  77. }