ecies.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
  2. // Copyright (c) 2012 The Go Authors. All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are
  6. // met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above
  11. // copyright notice, this list of conditions and the following disclaimer
  12. // in the documentation and/or other materials provided with the
  13. // distribution.
  14. // * Neither the name of Google Inc. nor the names of its
  15. // contributors may be used to endorse or promote products derived from
  16. // this software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. package ecies
  30. import (
  31. "crypto/cipher"
  32. "crypto/ecdsa"
  33. "crypto/elliptic"
  34. "crypto/hmac"
  35. "crypto/subtle"
  36. "fmt"
  37. "hash"
  38. "io"
  39. "math/big"
  40. )
  41. var (
  42. ErrImport = fmt.Errorf("ecies: failed to import key")
  43. ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve")
  44. ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters")
  45. ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key")
  46. ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity")
  47. ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big")
  48. )
  49. // PublicKey is a representation of an elliptic curve public key.
  50. type PublicKey struct {
  51. X *big.Int
  52. Y *big.Int
  53. elliptic.Curve
  54. Params *ECIESParams
  55. }
  56. // Export an ECIES public key as an ECDSA public key.
  57. func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey {
  58. return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}
  59. }
  60. // Import an ECDSA public key as an ECIES public key.
  61. func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey {
  62. return &PublicKey{
  63. X: pub.X,
  64. Y: pub.Y,
  65. Curve: pub.Curve,
  66. Params: ParamsFromCurve(pub.Curve),
  67. }
  68. }
  69. // PrivateKey is a representation of an elliptic curve private key.
  70. type PrivateKey struct {
  71. PublicKey
  72. D *big.Int
  73. }
  74. // Export an ECIES private key as an ECDSA private key.
  75. func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey {
  76. pub := &prv.PublicKey
  77. pubECDSA := pub.ExportECDSA()
  78. return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D}
  79. }
  80. // Import an ECDSA private key as an ECIES private key.
  81. func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {
  82. pub := ImportECDSAPublic(&prv.PublicKey)
  83. return &PrivateKey{*pub, prv.D}
  84. }
  85. // Generate an elliptic curve public / private keypair. If params is nil,
  86. // the recommended default paramters for the key will be chosen.
  87. func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {
  88. pb, x, y, err := elliptic.GenerateKey(curve, rand)
  89. if err != nil {
  90. return
  91. }
  92. prv = new(PrivateKey)
  93. prv.PublicKey.X = x
  94. prv.PublicKey.Y = y
  95. prv.PublicKey.Curve = curve
  96. prv.D = new(big.Int).SetBytes(pb)
  97. if params == nil {
  98. params = ParamsFromCurve(curve)
  99. }
  100. prv.PublicKey.Params = params
  101. return
  102. }
  103. // MaxSharedKeyLength returns the maximum length of the shared key the
  104. // public key can produce.
  105. func MaxSharedKeyLength(pub *PublicKey) int {
  106. return (pub.Curve.Params().BitSize + 7) / 8
  107. }
  108. // ECDH key agreement method used to establish secret keys for encryption.
  109. func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) {
  110. if prv.PublicKey.Curve != pub.Curve {
  111. return nil, ErrInvalidCurve
  112. }
  113. if skLen+macLen > MaxSharedKeyLength(pub) {
  114. return nil, ErrSharedKeyTooBig
  115. }
  116. x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
  117. if x == nil {
  118. return nil, ErrSharedKeyIsPointAtInfinity
  119. }
  120. sk = make([]byte, skLen+macLen)
  121. skBytes := x.Bytes()
  122. copy(sk[len(sk)-len(skBytes):], skBytes)
  123. return sk, nil
  124. }
  125. var (
  126. ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data")
  127. ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long")
  128. ErrInvalidMessage = fmt.Errorf("ecies: invalid message")
  129. )
  130. var (
  131. big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)
  132. big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))
  133. )
  134. func incCounter(ctr []byte) {
  135. if ctr[3]++; ctr[3] != 0 {
  136. return
  137. } else if ctr[2]++; ctr[2] != 0 {
  138. return
  139. } else if ctr[1]++; ctr[1] != 0 {
  140. return
  141. } else if ctr[0]++; ctr[0] != 0 {
  142. return
  143. }
  144. return
  145. }
  146. // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
  147. func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {
  148. if s1 == nil {
  149. s1 = make([]byte, 0)
  150. }
  151. reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)
  152. if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {
  153. fmt.Println(big2To32M1)
  154. return nil, ErrKeyDataTooLong
  155. }
  156. counter := []byte{0, 0, 0, 1}
  157. k = make([]byte, 0)
  158. for i := 0; i <= reps; i++ {
  159. hash.Write(counter)
  160. hash.Write(z)
  161. hash.Write(s1)
  162. k = append(k, hash.Sum(nil)...)
  163. hash.Reset()
  164. incCounter(counter)
  165. }
  166. k = k[:kdLen]
  167. return
  168. }
  169. // messageTag computes the MAC of a message (called the tag) as per
  170. // SEC 1, 3.5.
  171. func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {
  172. mac := hmac.New(hash, km)
  173. mac.Write(msg)
  174. mac.Write(shared)
  175. tag := mac.Sum(nil)
  176. return tag
  177. }
  178. // Generate an initialisation vector for CTR mode.
  179. func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
  180. iv = make([]byte, params.BlockSize)
  181. _, err = io.ReadFull(rand, iv)
  182. return
  183. }
  184. // symEncrypt carries out CTR encryption using the block cipher specified in the
  185. // parameters.
  186. func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {
  187. c, err := params.Cipher(key)
  188. if err != nil {
  189. return
  190. }
  191. iv, err := generateIV(params, rand)
  192. if err != nil {
  193. return
  194. }
  195. ctr := cipher.NewCTR(c, iv)
  196. ct = make([]byte, len(m)+params.BlockSize)
  197. copy(ct, iv)
  198. ctr.XORKeyStream(ct[params.BlockSize:], m)
  199. return
  200. }
  201. // symDecrypt carries out CTR decryption using the block cipher specified in
  202. // the parameters
  203. func symDecrypt(rand io.Reader, params *ECIESParams, key, ct []byte) (m []byte, err error) {
  204. c, err := params.Cipher(key)
  205. if err != nil {
  206. return
  207. }
  208. ctr := cipher.NewCTR(c, ct[:params.BlockSize])
  209. m = make([]byte, len(ct)-params.BlockSize)
  210. ctr.XORKeyStream(m, ct[params.BlockSize:])
  211. return
  212. }
  213. // Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1.
  214. //
  215. // s1 and s2 contain shared information that is not part of the resulting
  216. // ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
  217. // shared information parameters aren't being used, they should be nil.
  218. func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
  219. params := pub.Params
  220. if params == nil {
  221. if params = ParamsFromCurve(pub.Curve); params == nil {
  222. err = ErrUnsupportedECIESParameters
  223. return
  224. }
  225. }
  226. R, err := GenerateKey(rand, pub.Curve, params)
  227. if err != nil {
  228. return
  229. }
  230. hash := params.Hash()
  231. z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
  232. if err != nil {
  233. return
  234. }
  235. K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
  236. if err != nil {
  237. return
  238. }
  239. Ke := K[:params.KeyLen]
  240. Km := K[params.KeyLen:]
  241. hash.Write(Km)
  242. Km = hash.Sum(nil)
  243. hash.Reset()
  244. em, err := symEncrypt(rand, params, Ke, m)
  245. if err != nil || len(em) <= params.BlockSize {
  246. return
  247. }
  248. d := messageTag(params.Hash, Km, em, s2)
  249. Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)
  250. ct = make([]byte, len(Rb)+len(em)+len(d))
  251. copy(ct, Rb)
  252. copy(ct[len(Rb):], em)
  253. copy(ct[len(Rb)+len(em):], d)
  254. return
  255. }
  256. // Decrypt decrypts an ECIES ciphertext.
  257. func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) {
  258. if c == nil || len(c) == 0 {
  259. err = ErrInvalidMessage
  260. return
  261. }
  262. params := prv.PublicKey.Params
  263. if params == nil {
  264. if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {
  265. err = ErrUnsupportedECIESParameters
  266. return
  267. }
  268. }
  269. hash := params.Hash()
  270. var (
  271. rLen int
  272. hLen int = hash.Size()
  273. mStart int
  274. mEnd int
  275. )
  276. switch c[0] {
  277. case 2, 3, 4:
  278. rLen = ((prv.PublicKey.Curve.Params().BitSize + 7) / 4)
  279. if len(c) < (rLen + hLen + 1) {
  280. err = ErrInvalidMessage
  281. return
  282. }
  283. default:
  284. err = ErrInvalidPublicKey
  285. return
  286. }
  287. mStart = rLen
  288. mEnd = len(c) - hLen
  289. R := new(PublicKey)
  290. R.Curve = prv.PublicKey.Curve
  291. R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
  292. if R.X == nil {
  293. err = ErrInvalidPublicKey
  294. return
  295. }
  296. if !R.Curve.IsOnCurve(R.X, R.Y) {
  297. err = ErrInvalidCurve
  298. return
  299. }
  300. z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
  301. if err != nil {
  302. return
  303. }
  304. K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
  305. if err != nil {
  306. return
  307. }
  308. Ke := K[:params.KeyLen]
  309. Km := K[params.KeyLen:]
  310. hash.Write(Km)
  311. Km = hash.Sum(nil)
  312. hash.Reset()
  313. d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
  314. if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
  315. err = ErrInvalidMessage
  316. return
  317. }
  318. m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd])
  319. return
  320. }