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