Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
70d31fb2
Commit
70d31fb2
authored
Sep 07, 2018
by
Elad
Committed by
Balint Gabor
Sep 07, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd/swarm: added password to ACT (#17598)
parent
580145e9
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
249 additions
and
168 deletions
+249
-168
access.go
cmd/swarm/access.go
+31
-16
access_test.go
cmd/swarm/access_test.go
+65
-111
main.go
cmd/swarm/main.go
+1
-0
act.go
swarm/api/act.go
+108
-41
file.go
swarm/testutil/file.go
+44
-0
No files found.
cmd/swarm/access.go
View file @
70d31fb2
...
@@ -51,7 +51,7 @@ func accessNewPass(ctx *cli.Context) {
...
@@ -51,7 +51,7 @@ func accessNewPass(ctx *cli.Context) {
password
=
getPassPhrase
(
""
,
0
,
makePasswordList
(
ctx
))
password
=
getPassPhrase
(
""
,
0
,
makePasswordList
(
ctx
))
dryRun
=
ctx
.
Bool
(
SwarmDryRunFlag
.
Name
)
dryRun
=
ctx
.
Bool
(
SwarmDryRunFlag
.
Name
)
)
)
accessKey
,
ae
,
err
=
api
.
DoPassword
New
(
ctx
,
password
,
salt
)
accessKey
,
ae
,
err
=
api
.
DoPassword
(
ctx
,
password
,
salt
)
if
err
!=
nil
{
if
err
!=
nil
{
utils
.
Fatalf
(
"error getting session key: %v"
,
err
)
utils
.
Fatalf
(
"error getting session key: %v"
,
err
)
}
}
...
@@ -85,7 +85,7 @@ func accessNewPK(ctx *cli.Context) {
...
@@ -85,7 +85,7 @@ func accessNewPK(ctx *cli.Context) {
granteePublicKey
=
ctx
.
String
(
SwarmAccessGrantKeyFlag
.
Name
)
granteePublicKey
=
ctx
.
String
(
SwarmAccessGrantKeyFlag
.
Name
)
dryRun
=
ctx
.
Bool
(
SwarmDryRunFlag
.
Name
)
dryRun
=
ctx
.
Bool
(
SwarmDryRunFlag
.
Name
)
)
)
sessionKey
,
ae
,
err
=
api
.
DoPK
New
(
ctx
,
privateKey
,
granteePublicKey
,
salt
)
sessionKey
,
ae
,
err
=
api
.
DoPK
(
ctx
,
privateKey
,
granteePublicKey
,
salt
)
if
err
!=
nil
{
if
err
!=
nil
{
utils
.
Fatalf
(
"error getting session key: %v"
,
err
)
utils
.
Fatalf
(
"error getting session key: %v"
,
err
)
}
}
...
@@ -110,23 +110,38 @@ func accessNewACT(ctx *cli.Context) {
...
@@ -110,23 +110,38 @@ func accessNewACT(ctx *cli.Context) {
}
}
var
(
var
(
ae
*
api
.
AccessEntry
ae
*
api
.
AccessEntry
actManifest
*
api
.
Manifest
actManifest
*
api
.
Manifest
accessKey
[]
byte
accessKey
[]
byte
err
error
err
error
ref
=
args
[
0
]
ref
=
args
[
0
]
grantees
=
[]
string
{}
pkGrantees
=
[]
string
{}
actFilename
=
ctx
.
String
(
SwarmAccessGrantKeysFlag
.
Name
)
passGrantees
=
[]
string
{}
privateKey
=
getPrivKey
(
ctx
)
pkGranteesFilename
=
ctx
.
String
(
SwarmAccessGrantKeysFlag
.
Name
)
dryRun
=
ctx
.
Bool
(
SwarmDryRunFlag
.
Name
)
passGranteesFilename
=
ctx
.
String
(
utils
.
PasswordFileFlag
.
Name
)
privateKey
=
getPrivKey
(
ctx
)
dryRun
=
ctx
.
Bool
(
SwarmDryRunFlag
.
Name
)
)
)
if
pkGranteesFilename
==
""
&&
passGranteesFilename
==
""
{
utils
.
Fatalf
(
"you have to provide either a grantee public-keys file or an encryption passwords file (or both)"
)
}
bytes
,
err
:=
ioutil
.
ReadFile
(
actFilename
)
if
pkGranteesFilename
!=
""
{
if
err
!=
nil
{
bytes
,
err
:=
ioutil
.
ReadFile
(
pkGranteesFilename
)
utils
.
Fatalf
(
"had an error reading the grantee public key list"
)
if
err
!=
nil
{
utils
.
Fatalf
(
"had an error reading the grantee public key list"
)
}
pkGrantees
=
strings
.
Split
(
string
(
bytes
),
"
\n
"
)
}
if
passGranteesFilename
!=
""
{
bytes
,
err
:=
ioutil
.
ReadFile
(
passGranteesFilename
)
if
err
!=
nil
{
utils
.
Fatalf
(
"could not read password filename: %v"
,
err
)
}
passGrantees
=
strings
.
Split
(
string
(
bytes
),
"
\n
"
)
}
}
grantees
=
strings
.
Split
(
string
(
bytes
),
"
\n
"
)
accessKey
,
ae
,
actManifest
,
err
=
api
.
DoACT
(
ctx
,
privateKey
,
salt
,
pkGrantees
,
passGrantees
)
accessKey
,
ae
,
actManifest
,
err
=
api
.
DoACTNew
(
ctx
,
privateKey
,
salt
,
grantees
)
if
err
!=
nil
{
if
err
!=
nil
{
utils
.
Fatalf
(
"error generating ACT manifest: %v"
,
err
)
utils
.
Fatalf
(
"error generating ACT manifest: %v"
,
err
)
}
}
...
...
cmd/swarm/access_test.go
View file @
70d31fb2
...
@@ -28,7 +28,6 @@ import (
...
@@ -28,7 +28,6 @@ import (
gorand
"math/rand"
gorand
"math/rand"
"net/http"
"net/http"
"os"
"os"
"path/filepath"
"strings"
"strings"
"testing"
"testing"
"time"
"time"
...
@@ -39,6 +38,12 @@ import (
...
@@ -39,6 +38,12 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/api"
swarm
"github.com/ethereum/go-ethereum/swarm/api/client"
swarm
"github.com/ethereum/go-ethereum/swarm/api/client"
"github.com/ethereum/go-ethereum/swarm/testutil"
)
const
(
hashRegexp
=
`[a-f\d]{128}`
data
=
"notsorandomdata"
)
)
var
DefaultCurve
=
crypto
.
S256
()
var
DefaultCurve
=
crypto
.
S256
()
...
@@ -53,23 +58,8 @@ func TestAccessPassword(t *testing.T) {
...
@@ -53,23 +58,8 @@ func TestAccessPassword(t *testing.T) {
defer
cluster
.
Shutdown
()
defer
cluster
.
Shutdown
()
proxyNode
:=
cluster
.
Nodes
[
0
]
proxyNode
:=
cluster
.
Nodes
[
0
]
// create a tmp file
dataFilename
:=
testutil
.
TempFileWithContent
(
t
,
data
)
tmp
,
err
:=
ioutil
.
TempDir
(
""
,
"swarm-test"
)
defer
os
.
RemoveAll
(
dataFilename
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
RemoveAll
(
tmp
)
// write data to file
data
:=
"notsorandomdata"
dataFilename
:=
filepath
.
Join
(
tmp
,
"data.txt"
)
err
=
ioutil
.
WriteFile
(
dataFilename
,
[]
byte
(
data
),
0666
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
hashRegexp
:=
`[a-f\d]{128}`
// upload the file with 'swarm up' and expect a hash
// upload the file with 'swarm up' and expect a hash
up
:=
runSwarm
(
t
,
up
:=
runSwarm
(
t
,
...
@@ -86,14 +76,14 @@ func TestAccessPassword(t *testing.T) {
...
@@ -86,14 +76,14 @@ func TestAccessPassword(t *testing.T) {
}
}
ref
:=
matches
[
0
]
ref
:=
matches
[
0
]
tmp
,
err
:=
ioutil
.
TempDir
(
""
,
"swarm-test"
)
password
:=
"smth"
passwordFilename
:=
filepath
.
Join
(
tmp
,
"password.txt"
)
err
=
ioutil
.
WriteFile
(
passwordFilename
,
[]
byte
(
password
),
0666
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
defer
os
.
RemoveAll
(
tmp
)
password
:=
"smth"
passwordFilename
:=
testutil
.
TempFileWithContent
(
t
,
"smth"
)
defer
os
.
RemoveAll
(
passwordFilename
)
up
=
runSwarm
(
t
,
up
=
runSwarm
(
t
,
"access"
,
"access"
,
...
@@ -193,12 +183,8 @@ func TestAccessPassword(t *testing.T) {
...
@@ -193,12 +183,8 @@ func TestAccessPassword(t *testing.T) {
t
.
Errorf
(
"expected decrypted data %q, got %q"
,
data
,
string
(
d
))
t
.
Errorf
(
"expected decrypted data %q, got %q"
,
data
,
string
(
d
))
}
}
wrongPasswordFilename
:=
filepath
.
Join
(
tmp
,
"password-wrong.txt"
)
wrongPasswordFilename
:=
testutil
.
TempFileWithContent
(
t
,
"just wr0ng"
)
defer
os
.
RemoveAll
(
wrongPasswordFilename
)
err
=
ioutil
.
WriteFile
(
wrongPasswordFilename
,
[]
byte
(
"just wr0ng"
),
0666
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
//download file with 'swarm down' with wrong password
//download file with 'swarm down' with wrong password
up
=
runSwarm
(
t
,
up
=
runSwarm
(
t
,
...
@@ -227,22 +213,8 @@ func TestAccessPK(t *testing.T) {
...
@@ -227,22 +213,8 @@ func TestAccessPK(t *testing.T) {
cluster
:=
newTestCluster
(
t
,
2
)
cluster
:=
newTestCluster
(
t
,
2
)
defer
cluster
.
Shutdown
()
defer
cluster
.
Shutdown
()
// create a tmp file
dataFilename
:=
testutil
.
TempFileWithContent
(
t
,
data
)
tmp
,
err
:=
ioutil
.
TempFile
(
""
,
"swarm-test"
)
defer
os
.
RemoveAll
(
dataFilename
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
tmp
.
Close
()
defer
os
.
Remove
(
tmp
.
Name
())
// write data to file
data
:=
"notsorandomdata"
_
,
err
=
io
.
WriteString
(
tmp
,
data
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
hashRegexp
:=
`[a-f\d]{128}`
// upload the file with 'swarm up' and expect a hash
// upload the file with 'swarm up' and expect a hash
up
:=
runSwarm
(
t
,
up
:=
runSwarm
(
t
,
...
@@ -250,7 +222,7 @@ func TestAccessPK(t *testing.T) {
...
@@ -250,7 +222,7 @@ func TestAccessPK(t *testing.T) {
cluster
.
Nodes
[
0
]
.
URL
,
cluster
.
Nodes
[
0
]
.
URL
,
"up"
,
"up"
,
"--encrypt"
,
"--encrypt"
,
tmp
.
Name
()
)
dataFilename
)
_
,
matches
:=
up
.
ExpectRegexp
(
hashRegexp
)
_
,
matches
:=
up
.
ExpectRegexp
(
hashRegexp
)
up
.
ExpectExit
()
up
.
ExpectExit
()
...
@@ -259,7 +231,6 @@ func TestAccessPK(t *testing.T) {
...
@@ -259,7 +231,6 @@ func TestAccessPK(t *testing.T) {
}
}
ref
:=
matches
[
0
]
ref
:=
matches
[
0
]
pk
:=
cluster
.
Nodes
[
0
]
.
PrivateKey
pk
:=
cluster
.
Nodes
[
0
]
.
PrivateKey
granteePubKey
:=
crypto
.
CompressPubkey
(
&
pk
.
PublicKey
)
granteePubKey
:=
crypto
.
CompressPubkey
(
&
pk
.
PublicKey
)
...
@@ -268,22 +239,15 @@ func TestAccessPK(t *testing.T) {
...
@@ -268,22 +239,15 @@ func TestAccessPK(t *testing.T) {
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
passFile
,
err
:=
ioutil
.
TempFile
(
""
,
"swarm-test"
)
passwordFilename
:=
testutil
.
TempFileWithContent
(
t
,
testPassphrase
)
if
err
!=
nil
{
defer
os
.
RemoveAll
(
passwordFilename
)
t
.
Fatal
(
err
)
}
defer
passFile
.
Close
()
defer
os
.
Remove
(
passFile
.
Name
())
_
,
err
=
io
.
WriteString
(
passFile
,
testPassphrase
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
publisherAccount
:=
getTestAccount
(
t
,
publisherDir
)
_
,
publisherAccount
:=
getTestAccount
(
t
,
publisherDir
)
up
=
runSwarm
(
t
,
up
=
runSwarm
(
t
,
"--bzzaccount"
,
"--bzzaccount"
,
publisherAccount
.
Address
.
String
(),
publisherAccount
.
Address
.
String
(),
"--password"
,
"--password"
,
pass
File
.
Name
()
,
pass
wordFilename
,
"--datadir"
,
"--datadir"
,
publisherDir
,
publisherDir
,
"--bzzapi"
,
"--bzzapi"
,
...
@@ -309,7 +273,7 @@ func TestAccessPK(t *testing.T) {
...
@@ -309,7 +273,7 @@ func TestAccessPK(t *testing.T) {
"--bzzaccount"
,
"--bzzaccount"
,
publisherAccount
.
Address
.
String
(),
publisherAccount
.
Address
.
String
(),
"--password"
,
"--password"
,
pass
File
.
Name
()
,
pass
wordFilename
,
"--datadir"
,
"--datadir"
,
publisherDir
,
publisherDir
,
"print-keys"
,
"print-keys"
,
...
@@ -390,37 +354,24 @@ func TestAccessACTScale(t *testing.T) {
...
@@ -390,37 +354,24 @@ func TestAccessACTScale(t *testing.T) {
testAccessACT
(
t
,
1000
)
testAccessACT
(
t
,
1000
)
}
}
// TestAccessACT tests the e2e creation, uploading and downloading of an ACT
type access control
// TestAccessACT tests the e2e creation, uploading and downloading of an ACT
access control with both EC keys AND password protection
// the test fires up a 3 node cluster, then randomly picks 2 nodes which will be acting as grantees to the data
// the test fires up a 3 node cluster, then randomly picks 2 nodes which will be acting as grantees to the data
// set
. the third node should fail decoding the reference as it will not be granted access. the publisher uploads through
// set
and also protects the ACT with a password. the third node should fail decoding the reference as it will not be granted access.
//
one of the nodes then disappears. If `bogusEntries` is bigger than 0, the test will generate the number of bogus act entries
//
the third node then then tries to download using a correct password (and succeeds) then uses a wrong password and fails.
// t
o test what happens at scale
// t
he publisher uploads through one of the nodes then disappears.
func
testAccessACT
(
t
*
testing
.
T
,
bogusEntries
int
)
{
func
testAccessACT
(
t
*
testing
.
T
,
bogusEntries
int
)
{
// Setup Swarm and upload a test file to it
// Setup Swarm and upload a test file to it
cluster
:=
newTestCluster
(
t
,
3
)
const
clusterSize
=
3
cluster
:=
newTestCluster
(
t
,
clusterSize
)
defer
cluster
.
Shutdown
()
defer
cluster
.
Shutdown
()
var
uploadThroughNode
=
cluster
.
Nodes
[
0
]
var
uploadThroughNode
=
cluster
.
Nodes
[
0
]
client
:=
swarm
.
NewClient
(
uploadThroughNode
.
URL
)
client
:=
swarm
.
NewClient
(
uploadThroughNode
.
URL
)
r1
:=
gorand
.
New
(
gorand
.
NewSource
(
time
.
Now
()
.
UnixNano
()))
r1
:=
gorand
.
New
(
gorand
.
NewSource
(
time
.
Now
()
.
UnixNano
()))
nodeToSkip
:=
r1
.
Intn
(
3
)
// a number between 0 and 2 (node indices in `cluster`)
nodeToSkip
:=
r1
.
Intn
(
clusterSize
)
// a number between 0 and 2 (node indices in `cluster`)
// create a tmp file
dataFilename
:=
testutil
.
TempFileWithContent
(
t
,
data
)
tmp
,
err
:=
ioutil
.
TempFile
(
""
,
"swarm-test"
)
defer
os
.
RemoveAll
(
dataFilename
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
tmp
.
Close
()
defer
os
.
Remove
(
tmp
.
Name
())
// write data to file
data
:=
"notsorandomdata"
_
,
err
=
io
.
WriteString
(
tmp
,
data
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
hashRegexp
:=
`[a-f\d]{128}`
// upload the file with 'swarm up' and expect a hash
// upload the file with 'swarm up' and expect a hash
up
:=
runSwarm
(
t
,
up
:=
runSwarm
(
t
,
...
@@ -428,7 +379,7 @@ func testAccessACT(t *testing.T, bogusEntries int) {
...
@@ -428,7 +379,7 @@ func testAccessACT(t *testing.T, bogusEntries int) {
cluster
.
Nodes
[
0
]
.
URL
,
cluster
.
Nodes
[
0
]
.
URL
,
"up"
,
"up"
,
"--encrypt"
,
"--encrypt"
,
tmp
.
Name
()
)
dataFilename
)
_
,
matches
:=
up
.
ExpectRegexp
(
hashRegexp
)
_
,
matches
:=
up
.
ExpectRegexp
(
hashRegexp
)
up
.
ExpectExit
()
up
.
ExpectExit
()
...
@@ -464,41 +415,25 @@ func testAccessACT(t *testing.T, bogusEntries int) {
...
@@ -464,41 +415,25 @@ func testAccessACT(t *testing.T, bogusEntries int) {
}
}
grantees
=
bogusGrantees
grantees
=
bogusGrantees
}
}
granteesPubkeyListFile
:=
testutil
.
TempFileWithContent
(
t
,
strings
.
Join
(
grantees
,
"
\n
"
))
granteesPubkeyListFile
,
err
:=
ioutil
.
TempFile
(
""
,
"grantees-pubkey-list"
)
defer
os
.
RemoveAll
(
granteesPubkeyListFile
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
granteesPubkeyListFile
.
Close
()
defer
os
.
Remove
(
granteesPubkeyListFile
.
Name
())
_
,
err
=
granteesPubkeyListFile
.
WriteString
(
strings
.
Join
(
grantees
,
"
\n
"
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
publisherDir
,
err
:=
ioutil
.
TempDir
(
""
,
"swarm-account-dir-temp"
)
publisherDir
,
err
:=
ioutil
.
TempDir
(
""
,
"swarm-account-dir-temp"
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
defer
os
.
RemoveAll
(
publisherDir
)
passFile
,
err
:=
ioutil
.
TempFile
(
""
,
"swarm-test"
)
passwordFilename
:=
testutil
.
TempFileWithContent
(
t
,
testPassphrase
)
if
err
!=
nil
{
defer
os
.
RemoveAll
(
passwordFilename
)
t
.
Fatal
(
err
)
actPasswordFilename
:=
testutil
.
TempFileWithContent
(
t
,
"smth"
)
}
defer
os
.
RemoveAll
(
actPasswordFilename
)
defer
passFile
.
Close
()
defer
os
.
Remove
(
passFile
.
Name
())
_
,
err
=
io
.
WriteString
(
passFile
,
testPassphrase
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
publisherAccount
:=
getTestAccount
(
t
,
publisherDir
)
_
,
publisherAccount
:=
getTestAccount
(
t
,
publisherDir
)
up
=
runSwarm
(
t
,
up
=
runSwarm
(
t
,
"--bzzaccount"
,
"--bzzaccount"
,
publisherAccount
.
Address
.
String
(),
publisherAccount
.
Address
.
String
(),
"--password"
,
"--password"
,
pass
File
.
Name
()
,
pass
wordFilename
,
"--datadir"
,
"--datadir"
,
publisherDir
,
publisherDir
,
"--bzzapi"
,
"--bzzapi"
,
...
@@ -507,7 +442,9 @@ func testAccessACT(t *testing.T, bogusEntries int) {
...
@@ -507,7 +442,9 @@ func testAccessACT(t *testing.T, bogusEntries int) {
"new"
,
"new"
,
"act"
,
"act"
,
"--grant-keys"
,
"--grant-keys"
,
granteesPubkeyListFile
.
Name
(),
granteesPubkeyListFile
,
"--password"
,
actPasswordFilename
,
ref
,
ref
,
)
)
...
@@ -523,7 +460,7 @@ func testAccessACT(t *testing.T, bogusEntries int) {
...
@@ -523,7 +460,7 @@ func testAccessACT(t *testing.T, bogusEntries int) {
"--bzzaccount"
,
"--bzzaccount"
,
publisherAccount
.
Address
.
String
(),
publisherAccount
.
Address
.
String
(),
"--password"
,
"--password"
,
pass
File
.
Name
()
,
pass
wordFilename
,
"--datadir"
,
"--datadir"
,
publisherDir
,
publisherDir
,
"print-keys"
,
"print-keys"
,
...
@@ -562,9 +499,7 @@ func testAccessACT(t *testing.T, bogusEntries int) {
...
@@ -562,9 +499,7 @@ func testAccessACT(t *testing.T, bogusEntries int) {
if
len
(
a
.
Salt
)
<
32
{
if
len
(
a
.
Salt
)
<
32
{
t
.
Fatalf
(
`got salt with length %v, expected not less the 32 bytes`
,
len
(
a
.
Salt
))
t
.
Fatalf
(
`got salt with length %v, expected not less the 32 bytes`
,
len
(
a
.
Salt
))
}
}
if
a
.
KdfParams
!=
nil
{
t
.
Fatal
(
"manifest access kdf params should be nil"
)
}
if
a
.
Publisher
!=
pkComp
{
if
a
.
Publisher
!=
pkComp
{
t
.
Fatal
(
"publisher key did not match"
)
t
.
Fatal
(
"publisher key did not match"
)
}
}
...
@@ -588,6 +523,25 @@ func testAccessACT(t *testing.T, bogusEntries int) {
...
@@ -588,6 +523,25 @@ func testAccessACT(t *testing.T, bogusEntries int) {
t
.
Fatalf
(
"should be a 401"
)
t
.
Fatalf
(
"should be a 401"
)
}
}
// try downloading using a password instead, using the unauthorized node
passwordUrl
:=
strings
.
Replace
(
url
,
"http://"
,
"http://:smth@"
,
-
1
)
response
,
err
=
httpClient
.
Get
(
passwordUrl
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
response
.
StatusCode
!=
http
.
StatusOK
{
t
.
Fatal
(
"should be a 200"
)
}
// now try with the wrong password, expect 401
passwordUrl
=
strings
.
Replace
(
url
,
"http://"
,
"http://:smthWrong@"
,
-
1
)
response
,
err
=
httpClient
.
Get
(
passwordUrl
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
response
.
StatusCode
!=
http
.
StatusUnauthorized
{
t
.
Fatal
(
"should be a 401"
)
}
continue
continue
}
}
...
...
cmd/swarm/main.go
View file @
70d31fb2
...
@@ -319,6 +319,7 @@ func init() {
...
@@ -319,6 +319,7 @@ func init() {
Flags
:
[]
cli
.
Flag
{
Flags
:
[]
cli
.
Flag
{
SwarmAccessGrantKeysFlag
,
SwarmAccessGrantKeysFlag
,
SwarmDryRunFlag
,
SwarmDryRunFlag
,
utils
.
PasswordFileFlag
,
},
},
Name
:
"act"
,
Name
:
"act"
,
Usage
:
"encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest"
,
Usage
:
"encrypts a reference with the node's private key and a given grantee's public key and embeds it into a root manifest"
,
...
...
swarm/api/act.go
View file @
70d31fb2
...
@@ -102,6 +102,7 @@ const AccessTypePass = AccessType("pass")
...
@@ -102,6 +102,7 @@ const AccessTypePass = AccessType("pass")
const
AccessTypePK
=
AccessType
(
"pk"
)
const
AccessTypePK
=
AccessType
(
"pk"
)
const
AccessTypeACT
=
AccessType
(
"act"
)
const
AccessTypeACT
=
AccessType
(
"act"
)
// NewAccessEntryPassword creates a manifest AccessEntry in order to create an ACT protected by a password
func
NewAccessEntryPassword
(
salt
[]
byte
,
kdfParams
*
KdfParams
)
(
*
AccessEntry
,
error
)
{
func
NewAccessEntryPassword
(
salt
[]
byte
,
kdfParams
*
KdfParams
)
(
*
AccessEntry
,
error
)
{
if
len
(
salt
)
!=
32
{
if
len
(
salt
)
!=
32
{
return
nil
,
fmt
.
Errorf
(
"salt should be 32 bytes long"
)
return
nil
,
fmt
.
Errorf
(
"salt should be 32 bytes long"
)
...
@@ -113,6 +114,7 @@ func NewAccessEntryPassword(salt []byte, kdfParams *KdfParams) (*AccessEntry, er
...
@@ -113,6 +114,7 @@ func NewAccessEntryPassword(salt []byte, kdfParams *KdfParams) (*AccessEntry, er
},
nil
},
nil
}
}
// NewAccessEntryPK creates a manifest AccessEntry in order to create an ACT protected by a pair of Elliptic Curve keys
func
NewAccessEntryPK
(
publisher
string
,
salt
[]
byte
)
(
*
AccessEntry
,
error
)
{
func
NewAccessEntryPK
(
publisher
string
,
salt
[]
byte
)
(
*
AccessEntry
,
error
)
{
if
len
(
publisher
)
!=
66
{
if
len
(
publisher
)
!=
66
{
return
nil
,
fmt
.
Errorf
(
"publisher should be 66 characters long, got %d"
,
len
(
publisher
))
return
nil
,
fmt
.
Errorf
(
"publisher should be 66 characters long, got %d"
,
len
(
publisher
))
...
@@ -127,6 +129,7 @@ func NewAccessEntryPK(publisher string, salt []byte) (*AccessEntry, error) {
...
@@ -127,6 +129,7 @@ func NewAccessEntryPK(publisher string, salt []byte) (*AccessEntry, error) {
},
nil
},
nil
}
}
// NewAccessEntryACT creates a manifest AccessEntry in order to create an ACT protected by a combination of EC keys and passwords
func
NewAccessEntryACT
(
publisher
string
,
salt
[]
byte
,
act
string
)
(
*
AccessEntry
,
error
)
{
func
NewAccessEntryACT
(
publisher
string
,
salt
[]
byte
,
act
string
)
(
*
AccessEntry
,
error
)
{
if
len
(
salt
)
!=
32
{
if
len
(
salt
)
!=
32
{
return
nil
,
fmt
.
Errorf
(
"salt should be 32 bytes long"
)
return
nil
,
fmt
.
Errorf
(
"salt should be 32 bytes long"
)
...
@@ -140,15 +143,19 @@ func NewAccessEntryACT(publisher string, salt []byte, act string) (*AccessEntry,
...
@@ -140,15 +143,19 @@ func NewAccessEntryACT(publisher string, salt []byte, act string) (*AccessEntry,
Publisher
:
publisher
,
Publisher
:
publisher
,
Salt
:
salt
,
Salt
:
salt
,
Act
:
act
,
Act
:
act
,
KdfParams
:
DefaultKdfParams
,
},
nil
},
nil
}
}
// NOOPDecrypt is a generic decrypt function that is passed into the API in places where real ACT decryption capabilities are
// either unwanted, or alternatively, cannot be implemented in the immediate scope
func
NOOPDecrypt
(
*
ManifestEntry
)
error
{
func
NOOPDecrypt
(
*
ManifestEntry
)
error
{
return
nil
return
nil
}
}
var
DefaultKdfParams
=
NewKdfParams
(
262144
,
1
,
8
)
var
DefaultKdfParams
=
NewKdfParams
(
262144
,
1
,
8
)
// NewKdfParams returns a KdfParams struct with the given scrypt params
func
NewKdfParams
(
n
,
p
,
r
int
)
*
KdfParams
{
func
NewKdfParams
(
n
,
p
,
r
int
)
*
KdfParams
{
return
&
KdfParams
{
return
&
KdfParams
{
...
@@ -161,15 +168,20 @@ func NewKdfParams(n, p, r int) *KdfParams {
...
@@ -161,15 +168,20 @@ func NewKdfParams(n, p, r int) *KdfParams {
// NewSessionKeyPassword creates a session key based on a shared secret (password) and the given salt
// NewSessionKeyPassword creates a session key based on a shared secret (password) and the given salt
// and kdf parameters in the access entry
// and kdf parameters in the access entry
func
NewSessionKeyPassword
(
password
string
,
accessEntry
*
AccessEntry
)
([]
byte
,
error
)
{
func
NewSessionKeyPassword
(
password
string
,
accessEntry
*
AccessEntry
)
([]
byte
,
error
)
{
if
accessEntry
.
Type
!=
AccessTypePass
{
if
accessEntry
.
Type
!=
AccessTypePass
&&
accessEntry
.
Type
!=
AccessTypeACT
{
return
nil
,
errors
.
New
(
"incorrect access entry type"
)
return
nil
,
errors
.
New
(
"incorrect access entry type"
)
}
}
return
sessionKeyPassword
(
password
,
accessEntry
.
Salt
,
accessEntry
.
KdfParams
)
}
func
sessionKeyPassword
(
password
string
,
salt
[]
byte
,
kdfParams
*
KdfParams
)
([]
byte
,
error
)
{
return
scrypt
.
Key
(
return
scrypt
.
Key
(
[]
byte
(
password
),
[]
byte
(
password
),
accessEntry
.
S
alt
,
s
alt
,
accessEntry
.
K
dfParams
.
N
,
k
dfParams
.
N
,
accessEntry
.
K
dfParams
.
R
,
k
dfParams
.
R
,
accessEntry
.
K
dfParams
.
P
,
k
dfParams
.
P
,
32
,
32
,
)
)
}
}
...
@@ -188,9 +200,6 @@ func NewSessionKeyPK(private *ecdsa.PrivateKey, public *ecdsa.PublicKey, salt []
...
@@ -188,9 +200,6 @@ func NewSessionKeyPK(private *ecdsa.PrivateKey, public *ecdsa.PublicKey, salt []
return
sessionKey
,
nil
return
sessionKey
,
nil
}
}
func
(
a
*
API
)
NodeSessionKey
(
privateKey
*
ecdsa
.
PrivateKey
,
publicKey
*
ecdsa
.
PublicKey
,
salt
[]
byte
)
([]
byte
,
error
)
{
return
NewSessionKeyPK
(
privateKey
,
publicKey
,
salt
)
}
func
(
a
*
API
)
doDecrypt
(
ctx
context
.
Context
,
credentials
string
,
pk
*
ecdsa
.
PrivateKey
)
DecryptFunc
{
func
(
a
*
API
)
doDecrypt
(
ctx
context
.
Context
,
credentials
string
,
pk
*
ecdsa
.
PrivateKey
)
DecryptFunc
{
return
func
(
m
*
ManifestEntry
)
error
{
return
func
(
m
*
ManifestEntry
)
error
{
if
m
.
Access
==
nil
{
if
m
.
Access
==
nil
{
...
@@ -242,7 +251,7 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
...
@@ -242,7 +251,7 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
if
err
!=
nil
{
if
err
!=
nil
{
return
ErrDecrypt
return
ErrDecrypt
}
}
key
,
err
:=
a
.
NodeSessionKey
(
pk
,
publisher
,
m
.
Access
.
Salt
)
key
,
err
:=
NewSessionKeyPK
(
pk
,
publisher
,
m
.
Access
.
Salt
)
if
err
!=
nil
{
if
err
!=
nil
{
return
ErrDecrypt
return
ErrDecrypt
}
}
...
@@ -261,6 +270,11 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
...
@@ -261,6 +270,11 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
m
.
Access
=
nil
m
.
Access
=
nil
return
nil
return
nil
case
"act"
:
case
"act"
:
var
(
sessionKey
[]
byte
err
error
)
publisherBytes
,
err
:=
hex
.
DecodeString
(
m
.
Access
.
Publisher
)
publisherBytes
,
err
:=
hex
.
DecodeString
(
m
.
Access
.
Publisher
)
if
err
!=
nil
{
if
err
!=
nil
{
return
ErrDecrypt
return
ErrDecrypt
...
@@ -270,40 +284,35 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
...
@@ -270,40 +284,35 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
return
ErrDecrypt
return
ErrDecrypt
}
}
sessionKey
,
err
:=
a
.
NodeSessionKey
(
pk
,
publisher
,
m
.
Access
.
Salt
)
sessionKey
,
err
=
NewSessionKeyPK
(
pk
,
publisher
,
m
.
Access
.
Salt
)
if
err
!=
nil
{
if
err
!=
nil
{
return
ErrDecrypt
return
ErrDecrypt
}
}
hasher
:=
sha3
.
NewKeccak256
()
found
,
ciphertext
,
decryptionKey
,
err
:=
a
.
getACTDecryptionKey
(
ctx
,
storage
.
Address
(
common
.
Hex2Bytes
(
m
.
Access
.
Act
)),
sessionKey
)
hasher
.
Write
(
append
(
sessionKey
,
0
))
lookupKey
:=
hasher
.
Sum
(
nil
)
hasher
.
Reset
()
hasher
.
Write
(
append
(
sessionKey
,
1
))
accessKeyDecryptionKey
:=
hasher
.
Sum
(
nil
)
lk
:=
hex
.
EncodeToString
(
lookupKey
)
list
,
err
:=
a
.
GetManifestList
(
ctx
,
NOOPDecrypt
,
storage
.
Address
(
common
.
Hex2Bytes
(
m
.
Access
.
Act
)),
lk
)
found
:=
""
for
_
,
v
:=
range
list
.
Entries
{
if
v
.
Path
==
lk
{
found
=
v
.
Hash
}
}
if
found
==
""
{
return
ErrDecrypt
}
v
,
err
:=
hex
.
DecodeString
(
found
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
enc
:=
NewRefEncryption
(
len
(
v
)
-
8
)
if
!
found
{
decodedRef
,
err
:=
enc
.
Decrypt
(
v
,
accessKeyDecryptionKey
)
// try to fall back to password
if
credentials
!=
""
{
sessionKey
,
err
=
NewSessionKeyPassword
(
credentials
,
m
.
Access
)
if
err
!=
nil
{
return
err
}
found
,
ciphertext
,
decryptionKey
,
err
=
a
.
getACTDecryptionKey
(
ctx
,
storage
.
Address
(
common
.
Hex2Bytes
(
m
.
Access
.
Act
)),
sessionKey
)
if
err
!=
nil
{
return
err
}
if
!
found
{
return
ErrDecrypt
}
}
else
{
return
ErrDecrypt
}
}
enc
:=
NewRefEncryption
(
len
(
ciphertext
)
-
8
)
decodedRef
,
err
:=
enc
.
Decrypt
(
ciphertext
,
decryptionKey
)
if
err
!=
nil
{
if
err
!=
nil
{
return
ErrDecrypt
return
ErrDecrypt
}
}
...
@@ -326,6 +335,33 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
...
@@ -326,6 +335,33 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
}
}
}
}
func
(
a
*
API
)
getACTDecryptionKey
(
ctx
context
.
Context
,
actManifestAddress
storage
.
Address
,
sessionKey
[]
byte
)
(
found
bool
,
ciphertext
,
decryptionKey
[]
byte
,
err
error
)
{
hasher
:=
sha3
.
NewKeccak256
()
hasher
.
Write
(
append
(
sessionKey
,
0
))
lookupKey
:=
hasher
.
Sum
(
nil
)
hasher
.
Reset
()
hasher
.
Write
(
append
(
sessionKey
,
1
))
accessKeyDecryptionKey
:=
hasher
.
Sum
(
nil
)
hasher
.
Reset
()
lk
:=
hex
.
EncodeToString
(
lookupKey
)
list
,
err
:=
a
.
GetManifestList
(
ctx
,
NOOPDecrypt
,
actManifestAddress
,
lk
)
if
err
!=
nil
{
return
false
,
nil
,
nil
,
err
}
for
_
,
v
:=
range
list
.
Entries
{
if
v
.
Path
==
lk
{
cipherTextBytes
,
err
:=
hex
.
DecodeString
(
v
.
Hash
)
if
err
!=
nil
{
return
false
,
nil
,
nil
,
err
}
return
true
,
cipherTextBytes
,
accessKeyDecryptionKey
,
nil
}
}
return
false
,
nil
,
nil
,
nil
}
func
GenerateAccessControlManifest
(
ctx
*
cli
.
Context
,
ref
string
,
accessKey
[]
byte
,
ae
*
AccessEntry
)
(
*
Manifest
,
error
)
{
func
GenerateAccessControlManifest
(
ctx
*
cli
.
Context
,
ref
string
,
accessKey
[]
byte
,
ae
*
AccessEntry
)
(
*
Manifest
,
error
)
{
refBytes
,
err
:=
hex
.
DecodeString
(
ref
)
refBytes
,
err
:=
hex
.
DecodeString
(
ref
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -352,7 +388,9 @@ func GenerateAccessControlManifest(ctx *cli.Context, ref string, accessKey []byt
...
@@ -352,7 +388,9 @@ func GenerateAccessControlManifest(ctx *cli.Context, ref string, accessKey []byt
return
m
,
nil
return
m
,
nil
}
}
func
DoPKNew
(
ctx
*
cli
.
Context
,
privateKey
*
ecdsa
.
PrivateKey
,
granteePublicKey
string
,
salt
[]
byte
)
(
sessionKey
[]
byte
,
ae
*
AccessEntry
,
err
error
)
{
// DoPK is a helper function to the CLI API that handles the entire business logic for
// creating a session key and access entry given the cli context, ec keys and salt
func
DoPK
(
ctx
*
cli
.
Context
,
privateKey
*
ecdsa
.
PrivateKey
,
granteePublicKey
string
,
salt
[]
byte
)
(
sessionKey
[]
byte
,
ae
*
AccessEntry
,
err
error
)
{
if
granteePublicKey
==
""
{
if
granteePublicKey
==
""
{
return
nil
,
nil
,
errors
.
New
(
"need a grantee Public Key"
)
return
nil
,
nil
,
errors
.
New
(
"need a grantee Public Key"
)
}
}
...
@@ -383,9 +421,11 @@ func DoPKNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, granteePublicKey st
...
@@ -383,9 +421,11 @@ func DoPKNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, granteePublicKey st
return
sessionKey
,
ae
,
nil
return
sessionKey
,
ae
,
nil
}
}
func
DoACTNew
(
ctx
*
cli
.
Context
,
privateKey
*
ecdsa
.
PrivateKey
,
salt
[]
byte
,
grantees
[]
string
)
(
accessKey
[]
byte
,
ae
*
AccessEntry
,
actManifest
*
Manifest
,
err
error
)
{
// DoACT is a helper function to the CLI API that handles the entire business logic for
if
len
(
grantees
)
==
0
{
// creating a access key, access entry and ACT manifest (including uploading it) given the cli context, ec keys, password grantees and salt
return
nil
,
nil
,
nil
,
errors
.
New
(
"did not get any grantee public keys"
)
func
DoACT
(
ctx
*
cli
.
Context
,
privateKey
*
ecdsa
.
PrivateKey
,
salt
[]
byte
,
grantees
[]
string
,
encryptPasswords
[]
string
)
(
accessKey
[]
byte
,
ae
*
AccessEntry
,
actManifest
*
Manifest
,
err
error
)
{
if
len
(
grantees
)
==
0
&&
len
(
encryptPasswords
)
==
0
{
return
nil
,
nil
,
nil
,
errors
.
New
(
"did not get any grantee public keys or any encryption passwords"
)
}
}
publisherPub
:=
hex
.
EncodeToString
(
crypto
.
CompressPubkey
(
&
privateKey
.
PublicKey
))
publisherPub
:=
hex
.
EncodeToString
(
crypto
.
CompressPubkey
(
&
privateKey
.
PublicKey
))
...
@@ -430,7 +470,31 @@ func DoACTNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grant
...
@@ -430,7 +470,31 @@ func DoACTNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grant
enc
:=
NewRefEncryption
(
len
(
accessKey
))
enc
:=
NewRefEncryption
(
len
(
accessKey
))
encryptedAccessKey
,
err
:=
enc
.
Encrypt
(
accessKey
,
accessKeyEncryptionKey
)
encryptedAccessKey
,
err
:=
enc
.
Encrypt
(
accessKey
,
accessKeyEncryptionKey
)
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
lookupPathEncryptedAccessKeyMap
[
hex
.
EncodeToString
(
lookupKey
)]
=
hex
.
EncodeToString
(
encryptedAccessKey
)
}
for
_
,
pass
:=
range
encryptPasswords
{
sessionKey
,
err
:=
sessionKeyPassword
(
pass
,
salt
,
DefaultKdfParams
)
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
hasher
:=
sha3
.
NewKeccak256
()
hasher
.
Write
(
append
(
sessionKey
,
0
))
lookupKey
:=
hasher
.
Sum
(
nil
)
hasher
.
Reset
()
hasher
.
Write
(
append
(
sessionKey
,
1
))
accessKeyEncryptionKey
:=
hasher
.
Sum
(
nil
)
enc
:=
NewRefEncryption
(
len
(
accessKey
))
encryptedAccessKey
,
err
:=
enc
.
Encrypt
(
accessKey
,
accessKeyEncryptionKey
)
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
lookupPathEncryptedAccessKeyMap
[
hex
.
EncodeToString
(
lookupKey
)]
=
hex
.
EncodeToString
(
encryptedAccessKey
)
lookupPathEncryptedAccessKeyMap
[
hex
.
EncodeToString
(
lookupKey
)]
=
hex
.
EncodeToString
(
encryptedAccessKey
)
}
}
...
@@ -454,7 +518,10 @@ func DoACTNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grant
...
@@ -454,7 +518,10 @@ func DoACTNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grant
return
accessKey
,
ae
,
m
,
nil
return
accessKey
,
ae
,
m
,
nil
}
}
func
DoPasswordNew
(
ctx
*
cli
.
Context
,
password
string
,
salt
[]
byte
)
(
sessionKey
[]
byte
,
ae
*
AccessEntry
,
err
error
)
{
// DoPassword is a helper function to the CLI API that handles the entire business logic for
// creating a session key and an access entry given the cli context, password and salt.
// By default - DefaultKdfParams are used as the scrypt params
func
DoPassword
(
ctx
*
cli
.
Context
,
password
string
,
salt
[]
byte
)
(
sessionKey
[]
byte
,
ae
*
AccessEntry
,
err
error
)
{
ae
,
err
=
NewAccessEntryPassword
(
salt
,
DefaultKdfParams
)
ae
,
err
=
NewAccessEntryPassword
(
salt
,
DefaultKdfParams
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
err
...
...
swarm/testutil/file.go
0 → 100644
View file @
70d31fb2
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
testutil
import
(
"io"
"io/ioutil"
"os"
"strings"
"testing"
)
// TempFileWithContent is a helper function that creates a temp file that contains the following string content then closes the file handle
// it returns the complete file path
func
TempFileWithContent
(
t
*
testing
.
T
,
content
string
)
string
{
tempFile
,
err
:=
ioutil
.
TempFile
(
""
,
"swarm-temp-file"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
err
=
io
.
Copy
(
tempFile
,
strings
.
NewReader
(
content
))
if
err
!=
nil
{
os
.
RemoveAll
(
tempFile
.
Name
())
t
.
Fatal
(
err
)
}
if
err
=
tempFile
.
Close
();
err
!=
nil
{
t
.
Fatal
(
err
)
}
return
tempFile
.
Name
()
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment