github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/api/act.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 12:09:46</date> 10 //</624342668259889152> 11 12 package api 13 14 import ( 15 "context" 16 "crypto/ecdsa" 17 "crypto/rand" 18 "encoding/hex" 19 "encoding/json" 20 "errors" 21 "fmt" 22 "io" 23 "strings" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/crypto/ecies" 29 "github.com/ethereum/go-ethereum/crypto/sha3" 30 "github.com/ethereum/go-ethereum/swarm/log" 31 "github.com/ethereum/go-ethereum/swarm/sctx" 32 "github.com/ethereum/go-ethereum/swarm/storage" 33 "golang.org/x/crypto/scrypt" 34 cli "gopkg.in/urfave/cli.v1" 35 ) 36 37 var ( 38 ErrDecrypt = errors.New("cant decrypt - forbidden") 39 ErrUnknownAccessType = errors.New("unknown access type (or not implemented)") 40 ErrDecryptDomainForbidden = errors.New("decryption request domain forbidden - can only decrypt on localhost") 41 AllowedDecryptDomains = []string{ 42 "localhost", 43 "127.0.0.1", 44 } 45 ) 46 47 const EMPTY_CREDENTIALS = "" 48 49 type AccessEntry struct { 50 Type AccessType 51 Publisher string 52 Salt []byte 53 Act string 54 KdfParams *KdfParams 55 } 56 57 type DecryptFunc func(*ManifestEntry) error 58 59 func (a *AccessEntry) MarshalJSON() (out []byte, err error) { 60 61 return json.Marshal(struct { 62 Type AccessType `json:"type,omitempty"` 63 Publisher string `json:"publisher,omitempty"` 64 Salt string `json:"salt,omitempty"` 65 Act string `json:"act,omitempty"` 66 KdfParams *KdfParams `json:"kdf_params,omitempty"` 67 }{ 68 Type: a.Type, 69 Publisher: a.Publisher, 70 Salt: hex.EncodeToString(a.Salt), 71 Act: a.Act, 72 KdfParams: a.KdfParams, 73 }) 74 75 } 76 77 func (a *AccessEntry) UnmarshalJSON(value []byte) error { 78 v := struct { 79 Type AccessType `json:"type,omitempty"` 80 Publisher string `json:"publisher,omitempty"` 81 Salt string `json:"salt,omitempty"` 82 Act string `json:"act,omitempty"` 83 KdfParams *KdfParams `json:"kdf_params,omitempty"` 84 }{} 85 86 err := json.Unmarshal(value, &v) 87 if err != nil { 88 return err 89 } 90 a.Act = v.Act 91 a.KdfParams = v.KdfParams 92 a.Publisher = v.Publisher 93 a.Salt, err = hex.DecodeString(v.Salt) 94 if err != nil { 95 return err 96 } 97 if len(a.Salt) != 32 { 98 return errors.New("salt should be 32 bytes long") 99 } 100 a.Type = v.Type 101 return nil 102 } 103 104 type KdfParams struct { 105 N int `json:"n"` 106 P int `json:"p"` 107 R int `json:"r"` 108 } 109 110 type AccessType string 111 112 const AccessTypePass = AccessType("pass") 113 const AccessTypePK = AccessType("pk") 114 const AccessTypeACT = AccessType("act") 115 116 func NewAccessEntryPassword(salt []byte, kdfParams *KdfParams) (*AccessEntry, error) { 117 if len(salt) != 32 { 118 return nil, fmt.Errorf("salt should be 32 bytes long") 119 } 120 return &AccessEntry{ 121 Type: AccessTypePass, 122 Salt: salt, 123 KdfParams: kdfParams, 124 }, nil 125 } 126 127 func NewAccessEntryPK(publisher string, salt []byte) (*AccessEntry, error) { 128 if len(publisher) != 66 { 129 return nil, fmt.Errorf("publisher should be 66 characters long, got %d", len(publisher)) 130 } 131 if len(salt) != 32 { 132 return nil, fmt.Errorf("salt should be 32 bytes long") 133 } 134 return &AccessEntry{ 135 Type: AccessTypePK, 136 Publisher: publisher, 137 Salt: salt, 138 }, nil 139 } 140 141 func NewAccessEntryACT(publisher string, salt []byte, act string) (*AccessEntry, error) { 142 if len(salt) != 32 { 143 return nil, fmt.Errorf("salt should be 32 bytes long") 144 } 145 if len(publisher) != 66 { 146 return nil, fmt.Errorf("publisher should be 66 characters long") 147 } 148 149 return &AccessEntry{ 150 Type: AccessTypeACT, 151 Publisher: publisher, 152 Salt: salt, 153 Act: act, 154 }, nil 155 } 156 157 func NOOPDecrypt(*ManifestEntry) error { 158 return nil 159 } 160 161 var DefaultKdfParams = NewKdfParams(262144, 1, 8) 162 163 func NewKdfParams(n, p, r int) *KdfParams { 164 165 return &KdfParams{ 166 N: n, 167 P: p, 168 R: r, 169 } 170 } 171 172 //newsessionkeypassword基于共享机密(密码)和给定的salt创建会话密钥 173 //和访问项中的kdf参数 174 func NewSessionKeyPassword(password string, accessEntry *AccessEntry) ([]byte, error) { 175 if accessEntry.Type != AccessTypePass { 176 return nil, errors.New("incorrect access entry type") 177 } 178 return scrypt.Key( 179 []byte(password), 180 accessEntry.Salt, 181 accessEntry.KdfParams.N, 182 accessEntry.KdfParams.R, 183 accessEntry.KdfParams.P, 184 32, 185 ) 186 } 187 188 //newsessionkeypk为给定的密钥对和给定的salt值使用ECDH共享机密创建新的act会话密钥 189 func NewSessionKeyPK(private *ecdsa.PrivateKey, public *ecdsa.PublicKey, salt []byte) ([]byte, error) { 190 granteePubEcies := ecies.ImportECDSAPublic(public) 191 privateKey := ecies.ImportECDSA(private) 192 193 bytes, err := privateKey.GenerateShared(granteePubEcies, 16, 16) 194 if err != nil { 195 return nil, err 196 } 197 bytes = append(salt, bytes...) 198 sessionKey := crypto.Keccak256(bytes) 199 return sessionKey, nil 200 } 201 202 func (a *API) NodeSessionKey(privateKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, salt []byte) ([]byte, error) { 203 return NewSessionKeyPK(privateKey, publicKey, salt) 204 } 205 func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.PrivateKey) DecryptFunc { 206 return func(m *ManifestEntry) error { 207 if m.Access == nil { 208 return nil 209 } 210 211 allowed := false 212 requestDomain := sctx.GetHost(ctx) 213 for _, v := range AllowedDecryptDomains { 214 if strings.Contains(requestDomain, v) { 215 allowed = true 216 } 217 } 218 219 if !allowed { 220 return ErrDecryptDomainForbidden 221 } 222 223 switch m.Access.Type { 224 case "pass": 225 if credentials != "" { 226 key, err := NewSessionKeyPassword(credentials, m.Access) 227 if err != nil { 228 return err 229 } 230 231 ref, err := hex.DecodeString(m.Hash) 232 if err != nil { 233 return err 234 } 235 236 enc := NewRefEncryption(len(ref) - 8) 237 decodedRef, err := enc.Decrypt(ref, key) 238 if err != nil { 239 return ErrDecrypt 240 } 241 242 m.Hash = hex.EncodeToString(decodedRef) 243 m.Access = nil 244 return nil 245 } 246 return ErrDecrypt 247 case "pk": 248 publisherBytes, err := hex.DecodeString(m.Access.Publisher) 249 if err != nil { 250 return ErrDecrypt 251 } 252 publisher, err := crypto.DecompressPubkey(publisherBytes) 253 if err != nil { 254 return ErrDecrypt 255 } 256 key, err := a.NodeSessionKey(pk, publisher, m.Access.Salt) 257 if err != nil { 258 return ErrDecrypt 259 } 260 ref, err := hex.DecodeString(m.Hash) 261 if err != nil { 262 return err 263 } 264 265 enc := NewRefEncryption(len(ref) - 8) 266 decodedRef, err := enc.Decrypt(ref, key) 267 if err != nil { 268 return ErrDecrypt 269 } 270 271 m.Hash = hex.EncodeToString(decodedRef) 272 m.Access = nil 273 return nil 274 case "act": 275 publisherBytes, err := hex.DecodeString(m.Access.Publisher) 276 if err != nil { 277 return ErrDecrypt 278 } 279 publisher, err := crypto.DecompressPubkey(publisherBytes) 280 if err != nil { 281 return ErrDecrypt 282 } 283 284 sessionKey, err := a.NodeSessionKey(pk, publisher, m.Access.Salt) 285 if err != nil { 286 return ErrDecrypt 287 } 288 289 hasher := sha3.NewKeccak256() 290 hasher.Write(append(sessionKey, 0)) 291 lookupKey := hasher.Sum(nil) 292 293 hasher.Reset() 294 295 hasher.Write(append(sessionKey, 1)) 296 accessKeyDecryptionKey := hasher.Sum(nil) 297 298 lk := hex.EncodeToString(lookupKey) 299 list, err := a.GetManifestList(ctx, NOOPDecrypt, storage.Address(common.Hex2Bytes(m.Access.Act)), lk) 300 301 found := "" 302 for _, v := range list.Entries { 303 if v.Path == lk { 304 found = v.Hash 305 } 306 } 307 308 if found == "" { 309 return ErrDecrypt 310 } 311 312 v, err := hex.DecodeString(found) 313 if err != nil { 314 return err 315 } 316 enc := NewRefEncryption(len(v) - 8) 317 decodedRef, err := enc.Decrypt(v, accessKeyDecryptionKey) 318 if err != nil { 319 return ErrDecrypt 320 } 321 322 ref, err := hex.DecodeString(m.Hash) 323 if err != nil { 324 return err 325 } 326 327 enc = NewRefEncryption(len(ref) - 8) 328 decodedMainRef, err := enc.Decrypt(ref, decodedRef) 329 if err != nil { 330 return ErrDecrypt 331 } 332 m.Hash = hex.EncodeToString(decodedMainRef) 333 m.Access = nil 334 return nil 335 } 336 return ErrUnknownAccessType 337 } 338 } 339 340 func GenerateAccessControlManifest(ctx *cli.Context, ref string, accessKey []byte, ae *AccessEntry) (*Manifest, error) { 341 refBytes, err := hex.DecodeString(ref) 342 if err != nil { 343 return nil, err 344 } 345 //用accesskey加密ref 346 enc := NewRefEncryption(len(refBytes)) 347 encrypted, err := enc.Encrypt(refBytes, accessKey) 348 if err != nil { 349 return nil, err 350 } 351 352 m := &Manifest{ 353 Entries: []ManifestEntry{ 354 { 355 Hash: hex.EncodeToString(encrypted), 356 ContentType: ManifestType, 357 ModTime: time.Now(), 358 Access: ae, 359 }, 360 }, 361 } 362 363 return m, nil 364 } 365 366 func DoPKNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, granteePublicKey string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) { 367 if granteePublicKey == "" { 368 return nil, nil, errors.New("need a grantee Public Key") 369 } 370 b, err := hex.DecodeString(granteePublicKey) 371 if err != nil { 372 log.Error("error decoding grantee public key", "err", err) 373 return nil, nil, err 374 } 375 376 granteePub, err := crypto.DecompressPubkey(b) 377 if err != nil { 378 log.Error("error decompressing grantee public key", "err", err) 379 return nil, nil, err 380 } 381 382 sessionKey, err = NewSessionKeyPK(privateKey, granteePub, salt) 383 if err != nil { 384 log.Error("error getting session key", "err", err) 385 return nil, nil, err 386 } 387 388 ae, err = NewAccessEntryPK(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt) 389 if err != nil { 390 log.Error("error generating access entry", "err", err) 391 return nil, nil, err 392 } 393 394 return sessionKey, ae, nil 395 } 396 397 func DoACTNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees []string) (accessKey []byte, ae *AccessEntry, actManifest *Manifest, err error) { 398 if len(grantees) == 0 { 399 return nil, nil, nil, errors.New("did not get any grantee public keys") 400 } 401 402 publisherPub := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)) 403 grantees = append(grantees, publisherPub) 404 405 accessKey = make([]byte, 32) 406 if _, err := io.ReadFull(rand.Reader, salt); err != nil { 407 panic("reading from crypto/rand failed: " + err.Error()) 408 } 409 if _, err := io.ReadFull(rand.Reader, accessKey); err != nil { 410 panic("reading from crypto/rand failed: " + err.Error()) 411 } 412 413 lookupPathEncryptedAccessKeyMap := make(map[string]string) 414 i := 0 415 for _, v := range grantees { 416 i++ 417 if v == "" { 418 return nil, nil, nil, errors.New("need a grantee Public Key") 419 } 420 b, err := hex.DecodeString(v) 421 if err != nil { 422 log.Error("error decoding grantee public key", "err", err) 423 return nil, nil, nil, err 424 } 425 426 granteePub, err := crypto.DecompressPubkey(b) 427 if err != nil { 428 log.Error("error decompressing grantee public key", "err", err) 429 return nil, nil, nil, err 430 } 431 sessionKey, err := NewSessionKeyPK(privateKey, granteePub, salt) 432 433 hasher := sha3.NewKeccak256() 434 hasher.Write(append(sessionKey, 0)) 435 lookupKey := hasher.Sum(nil) 436 437 hasher.Reset() 438 hasher.Write(append(sessionKey, 1)) 439 440 accessKeyEncryptionKey := hasher.Sum(nil) 441 442 enc := NewRefEncryption(len(accessKey)) 443 encryptedAccessKey, err := enc.Encrypt(accessKey, accessKeyEncryptionKey) 444 445 lookupPathEncryptedAccessKeyMap[hex.EncodeToString(lookupKey)] = hex.EncodeToString(encryptedAccessKey) 446 } 447 448 m := &Manifest{ 449 Entries: []ManifestEntry{}, 450 } 451 452 for k, v := range lookupPathEncryptedAccessKeyMap { 453 m.Entries = append(m.Entries, ManifestEntry{ 454 Path: k, 455 Hash: v, 456 ContentType: "text/plain", 457 }) 458 } 459 460 ae, err = NewAccessEntryACT(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt, "") 461 if err != nil { 462 return nil, nil, nil, err 463 } 464 465 return accessKey, ae, m, nil 466 } 467 468 func DoPasswordNew(ctx *cli.Context, password string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) { 469 ae, err = NewAccessEntryPassword(salt, DefaultKdfParams) 470 if err != nil { 471 return nil, nil, err 472 } 473 474 sessionKey, err = NewSessionKeyPassword(password, ae) 475 if err != nil { 476 return nil, nil, err 477 } 478 return sessionKey, ae, nil 479 } 480