github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/crypto/ecies/ecies.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:36</date> 10 //</624450084968337409> 11 12 //版权所有(c)2013 Kyle Isom<kyle@tyrfingr.is> 13 //版权所有(c)2012 The Go作者。版权所有。 14 // 15 //以源和二进制形式重新分配和使用,有或无 16 //允许修改,前提是以下条件 17 //遇见: 18 // 19 //*源代码的再分配必须保留上述版权。 20 //注意,此条件列表和以下免责声明。 21 //*二进制形式的再分配必须复制上述内容 22 //版权声明、此条件列表和以下免责声明 23 //在提供的文件和/或其他材料中, 24 //分布。 25 //*无论是谷歌公司的名称还是其 26 //贡献者可用于支持或推广源自 27 //本软件未经事先明确书面许可。 28 // 29 //本软件由版权所有者和贡献者提供。 30 //“原样”和任何明示或暗示的保证,包括但不包括 31 //仅限于对适销性和适用性的暗示保证 32 //不承认特定目的。在任何情况下,版权 33 //所有人或出资人对任何直接、间接、附带的, 34 //特殊、惩戒性或后果性损害(包括但不包括 35 //仅限于采购替代货物或服务;使用损失, 36 //数据或利润;或业务中断),无论如何引起的 37 //责任理论,无论是合同责任、严格责任还是侵权责任。 38 //(包括疏忽或其他)因使用不当而引起的 39 //即使已告知此类损坏的可能性。 40 41 package ecies 42 43 import ( 44 "crypto/cipher" 45 "crypto/ecdsa" 46 "crypto/elliptic" 47 "crypto/hmac" 48 "crypto/subtle" 49 "fmt" 50 "hash" 51 "io" 52 "math/big" 53 ) 54 55 var ( 56 ErrImport = fmt.Errorf("ecies: failed to import key") 57 ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve") 58 ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters") 59 ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key") 60 ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity") 61 ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big") 62 ) 63 64 //公钥是椭圆曲线公钥的表示形式。 65 type PublicKey struct { 66 X *big.Int 67 Y *big.Int 68 elliptic.Curve 69 Params *ECIESParams 70 } 71 72 //将ECIES公钥导出为ECDSA公钥。 73 func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey { 74 return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y} 75 } 76 77 //将ECDSA公钥导入为特定的公钥。 78 func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey { 79 return &PublicKey{ 80 X: pub.X, 81 Y: pub.Y, 82 Curve: pub.Curve, 83 Params: ParamsFromCurve(pub.Curve), 84 } 85 } 86 87 //private key是椭圆曲线私钥的表示。 88 type PrivateKey struct { 89 PublicKey 90 D *big.Int 91 } 92 93 //Export an ECIES private key as an ECDSA private key. 94 func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey { 95 pub := &prv.PublicKey 96 pubECDSA := pub.ExportECDSA() 97 return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D} 98 } 99 100 //将ECDSA私钥导入为ECIES私钥。 101 func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { 102 pub := ImportECDSAPublic(&prv.PublicKey) 103 return &PrivateKey{*pub, prv.D} 104 } 105 106 //生成椭圆曲线公钥/私钥对。如果参数为零, 107 //the recommended default parameters for the key will be chosen. 108 func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { 109 pb, x, y, err := elliptic.GenerateKey(curve, rand) 110 if err != nil { 111 return 112 } 113 prv = new(PrivateKey) 114 prv.PublicKey.X = x 115 prv.PublicKey.Y = y 116 prv.PublicKey.Curve = curve 117 prv.D = new(big.Int).SetBytes(pb) 118 if params == nil { 119 params = ParamsFromCurve(curve) 120 } 121 prv.PublicKey.Params = params 122 return 123 } 124 125 //MaxSharedKeyLength返回共享密钥的最大长度 126 //可以生成公钥。 127 func MaxSharedKeyLength(pub *PublicKey) int { 128 return (pub.Curve.Params().BitSize + 7) / 8 129 } 130 131 //用于建立加密密钥的ECDH密钥协议方法。 132 func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) { 133 if prv.PublicKey.Curve != pub.Curve { 134 return nil, ErrInvalidCurve 135 } 136 if skLen+macLen > MaxSharedKeyLength(pub) { 137 return nil, ErrSharedKeyTooBig 138 } 139 140 x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes()) 141 if x == nil { 142 return nil, ErrSharedKeyIsPointAtInfinity 143 } 144 145 sk = make([]byte, skLen+macLen) 146 skBytes := x.Bytes() 147 copy(sk[len(sk)-len(skBytes):], skBytes) 148 return sk, nil 149 } 150 151 var ( 152 ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data") 153 ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long") 154 ErrInvalidMessage = fmt.Errorf("ecies: invalid message") 155 ) 156 157 var ( 158 big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil) 159 big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1)) 160 ) 161 162 func incCounter(ctr []byte) { 163 if ctr[3]++; ctr[3] != 0 { 164 return 165 } 166 if ctr[2]++; ctr[2] != 0 { 167 return 168 } 169 if ctr[1]++; ctr[1] != 0 { 170 return 171 } 172 if ctr[0]++; ctr[0] != 0 { 173 return 174 } 175 } 176 177 //NIST SP 800-56串联密钥派生函数(见第5.8.1节)。 178 func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) { 179 if s1 == nil { 180 s1 = make([]byte, 0) 181 } 182 183 reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8) 184 if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 { 185 fmt.Println(big2To32M1) 186 return nil, ErrKeyDataTooLong 187 } 188 189 counter := []byte{0, 0, 0, 1} 190 k = make([]byte, 0) 191 192 for i := 0; i <= reps; i++ { 193 hash.Write(counter) 194 hash.Write(z) 195 hash.Write(s1) 196 k = append(k, hash.Sum(nil)...) 197 hash.Reset() 198 incCounter(counter) 199 } 200 201 k = k[:kdLen] 202 return 203 } 204 205 //message tag根据 206 //秒1,3.5。 207 func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte { 208 mac := hmac.New(hash, km) 209 mac.Write(msg) 210 mac.Write(shared) 211 tag := mac.Sum(nil) 212 return tag 213 } 214 215 //为ctr模式生成初始化向量。 216 func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) { 217 iv = make([]byte, params.BlockSize) 218 _, err = io.ReadFull(rand, iv) 219 return 220 } 221 222 //symeencrypt使用中指定的块密码执行ctr加密 223 //参数。 224 func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) { 225 c, err := params.Cipher(key) 226 if err != nil { 227 return 228 } 229 230 iv, err := generateIV(params, rand) 231 if err != nil { 232 return 233 } 234 ctr := cipher.NewCTR(c, iv) 235 236 ct = make([]byte, len(m)+params.BlockSize) 237 copy(ct, iv) 238 ctr.XORKeyStream(ct[params.BlockSize:], m) 239 return 240 } 241 242 //symDecrypt carries out CTR decryption using the block cipher specified in 243 //参数 244 func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) { 245 c, err := params.Cipher(key) 246 if err != nil { 247 return 248 } 249 250 ctr := cipher.NewCTR(c, ct[:params.BlockSize]) 251 252 m = make([]byte, len(ct)-params.BlockSize) 253 ctr.XORKeyStream(m, ct[params.BlockSize:]) 254 return 255 } 256 257 //Encrypt使用第1节5.1中指定的ECIES对消息进行加密。 258 // 259 //s1和s2包含不属于结果的共享信息 260 //密文。s1被输入到键派生中,s2被输入到mac中。如果 261 //未使用共享信息参数,它们应为零。 262 func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) { 263 params := pub.Params 264 if params == nil { 265 if params = ParamsFromCurve(pub.Curve); params == nil { 266 err = ErrUnsupportedECIESParameters 267 return 268 } 269 } 270 R, err := GenerateKey(rand, pub.Curve, params) 271 if err != nil { 272 return 273 } 274 275 hash := params.Hash() 276 z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen) 277 if err != nil { 278 return 279 } 280 K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen) 281 if err != nil { 282 return 283 } 284 Ke := K[:params.KeyLen] 285 Km := K[params.KeyLen:] 286 hash.Write(Km) 287 Km = hash.Sum(nil) 288 hash.Reset() 289 290 em, err := symEncrypt(rand, params, Ke, m) 291 if err != nil || len(em) <= params.BlockSize { 292 return 293 } 294 295 d := messageTag(params.Hash, Km, em, s2) 296 297 Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y) 298 ct = make([]byte, len(Rb)+len(em)+len(d)) 299 copy(ct, Rb) 300 copy(ct[len(Rb):], em) 301 copy(ct[len(Rb)+len(em):], d) 302 return 303 } 304 305 //解密-解密特定的密文。 306 func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { 307 if len(c) == 0 { 308 return nil, ErrInvalidMessage 309 } 310 params := prv.PublicKey.Params 311 if params == nil { 312 if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil { 313 err = ErrUnsupportedECIESParameters 314 return 315 } 316 } 317 hash := params.Hash() 318 319 var ( 320 rLen int 321 hLen int = hash.Size() 322 mStart int 323 mEnd int 324 ) 325 326 switch c[0] { 327 case 2, 3, 4: 328 rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4 329 if len(c) < (rLen + hLen + 1) { 330 err = ErrInvalidMessage 331 return 332 } 333 default: 334 err = ErrInvalidPublicKey 335 return 336 } 337 338 mStart = rLen 339 mEnd = len(c) - hLen 340 341 R := new(PublicKey) 342 R.Curve = prv.PublicKey.Curve 343 R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen]) 344 if R.X == nil { 345 err = ErrInvalidPublicKey 346 return 347 } 348 if !R.Curve.IsOnCurve(R.X, R.Y) { 349 err = ErrInvalidCurve 350 return 351 } 352 353 z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) 354 if err != nil { 355 return 356 } 357 358 K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen) 359 if err != nil { 360 return 361 } 362 363 Ke := K[:params.KeyLen] 364 Km := K[params.KeyLen:] 365 hash.Write(Km) 366 Km = hash.Sum(nil) 367 hash.Reset() 368 369 d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) 370 if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { 371 err = ErrInvalidMessage 372 return 373 } 374 375 m, err = symDecrypt(params, Ke, c[mStart:mEnd]) 376 return 377 } 378