aboutsummaryrefslogtreecommitdiffstats
path: root/swarm
diff options
context:
space:
mode:
authorViktor TrĂ³n <viktor.tron@gmail.com>2018-09-11 17:39:02 +0800
committerBalint Gabor <balint.g@gmail.com>2018-09-11 17:39:02 +0800
commit6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9 (patch)
tree80c450335b3ad5b26214ecb7e145bdcdd58ac528 /swarm
parent10bac3664702f31228eafedecf31e9bf115f6c29 (diff)
downloadgo-tangerine-6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9.tar
go-tangerine-6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9.tar.gz
go-tangerine-6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9.tar.bz2
go-tangerine-6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9.tar.lz
go-tangerine-6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9.tar.xz
go-tangerine-6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9.tar.zst
go-tangerine-6dd87483d4ded2a5ab76d19e0acaa5c6b06312a9.zip
Encryption async api (#17603)
* swarm/storage/encryption: async segmentwise encryption/decryption * swarm/storage: adapt hasherstore to encryption API change * swarm/api: adapt RefEncryption for AC to new Encryption API * swarm/storage/encryption: address review comments
Diffstat (limited to 'swarm')
-rw-r--r--swarm/api/encrypt.go22
-rw-r--r--swarm/storage/encryption/encryption.go126
-rw-r--r--swarm/storage/encryption/encryption_test.go47
-rw-r--r--swarm/storage/hasherstore.go100
4 files changed, 170 insertions, 125 deletions
diff --git a/swarm/api/encrypt.go b/swarm/api/encrypt.go
index 9a2e36914..ffe6c16d2 100644
--- a/swarm/api/encrypt.go
+++ b/swarm/api/encrypt.go
@@ -25,27 +25,27 @@ import (
)
type RefEncryption struct {
- spanEncryption encryption.Encryption
- dataEncryption encryption.Encryption
- span []byte
+ refSize int
+ span []byte
}
func NewRefEncryption(refSize int) *RefEncryption {
span := make([]byte, 8)
binary.LittleEndian.PutUint64(span, uint64(refSize))
return &RefEncryption{
- spanEncryption: encryption.New(0, uint32(refSize/32), sha3.NewKeccak256),
- dataEncryption: encryption.New(refSize, 0, sha3.NewKeccak256),
- span: span,
+ refSize: refSize,
+ span: span,
}
}
func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) {
- encryptedSpan, err := re.spanEncryption.Encrypt(re.span, key)
+ spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewKeccak256)
+ encryptedSpan, err := spanEncryption.Encrypt(re.span)
if err != nil {
return nil, err
}
- encryptedData, err := re.dataEncryption.Encrypt(ref, key)
+ dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewKeccak256)
+ encryptedData, err := dataEncryption.Encrypt(ref)
if err != nil {
return nil, err
}
@@ -57,7 +57,8 @@ func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) {
}
func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) {
- decryptedSpan, err := re.spanEncryption.Decrypt(ref[:8], key)
+ spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewKeccak256)
+ decryptedSpan, err := spanEncryption.Decrypt(ref[:8])
if err != nil {
return nil, err
}
@@ -67,7 +68,8 @@ func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) {
return nil, errors.New("invalid span in encrypted reference")
}
- decryptedRef, err := re.dataEncryption.Decrypt(ref[8:], key)
+ dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewKeccak256)
+ decryptedRef, err := dataEncryption.Decrypt(ref[8:])
if err != nil {
return nil, err
}
diff --git a/swarm/storage/encryption/encryption.go b/swarm/storage/encryption/encryption.go
index e50f2163d..6fbdab062 100644
--- a/swarm/storage/encryption/encryption.go
+++ b/swarm/storage/encryption/encryption.go
@@ -21,6 +21,7 @@ import (
"encoding/binary"
"fmt"
"hash"
+ "sync"
)
const KeyLength = 32
@@ -28,84 +29,119 @@ const KeyLength = 32
type Key []byte
type Encryption interface {
- Encrypt(data []byte, key Key) ([]byte, error)
- Decrypt(data []byte, key Key) ([]byte, error)
+ Encrypt(data []byte) ([]byte, error)
+ Decrypt(data []byte) ([]byte, error)
}
type encryption struct {
- padding int
- initCtr uint32
- hashFunc func() hash.Hash
+ key Key // the encryption key (hashSize bytes long)
+ keyLen int // length of the key = length of blockcipher block
+ padding int // encryption will pad the data upto this if > 0
+ initCtr uint32 // initial counter used for counter mode blockcipher
+ hashFunc func() hash.Hash // hasher constructor function
}
-func New(padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption {
+// New constructs a new encryptor/decryptor
+func New(key Key, padding int, initCtr uint32, hashFunc func() hash.Hash) *encryption {
return &encryption{
+ key: key,
+ keyLen: len(key),
padding: padding,
initCtr: initCtr,
hashFunc: hashFunc,
}
}
-func (e *encryption) Encrypt(data []byte, key Key) ([]byte, error) {
+// Encrypt encrypts the data and does padding if specified
+func (e *encryption) Encrypt(data []byte) ([]byte, error) {
length := len(data)
+ outLength := length
isFixedPadding := e.padding > 0
- if isFixedPadding && length > e.padding {
- return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding)
- }
-
- paddedData := data
- if isFixedPadding && length < e.padding {
- paddedData = make([]byte, e.padding)
- copy(paddedData[:length], data)
- rand.Read(paddedData[length:])
+ if isFixedPadding {
+ if length > e.padding {
+ return nil, fmt.Errorf("Data length longer than padding, data length %v padding %v", length, e.padding)
+ }
+ outLength = e.padding
}
- return e.transform(paddedData, key), nil
+ out := make([]byte, outLength)
+ e.transform(data, out)
+ return out, nil
}
-func (e *encryption) Decrypt(data []byte, key Key) ([]byte, error) {
+// Decrypt decrypts the data, if padding was used caller must know original length and truncate
+func (e *encryption) Decrypt(data []byte) ([]byte, error) {
length := len(data)
if e.padding > 0 && length != e.padding {
return nil, fmt.Errorf("Data length different than padding, data length %v padding %v", length, e.padding)
}
+ out := make([]byte, length)
+ e.transform(data, out)
+ return out, nil
+}
- return e.transform(data, key), nil
+//
+func (e *encryption) transform(in, out []byte) {
+ inLength := len(in)
+ wg := sync.WaitGroup{}
+ wg.Add((inLength-1)/e.keyLen + 1)
+ for i := 0; i < inLength; i += e.keyLen {
+ l := min(e.keyLen, inLength-i)
+ // call transformations per segment (asyncronously)
+ go func(i int, x, y []byte) {
+ defer wg.Done()
+ e.Transcrypt(i, x, y)
+ }(i/e.keyLen, in[i:i+l], out[i:i+l])
+ }
+ // pad the rest if out is longer
+ pad(out[inLength:])
+ wg.Wait()
}
-func (e *encryption) transform(data []byte, key Key) []byte {
- dataLength := len(data)
- transformedData := make([]byte, dataLength)
+// used for segmentwise transformation
+// if in is shorter than out, padding is used
+func (e *encryption) Transcrypt(i int, in []byte, out []byte) {
+ // first hash key with counter (initial counter + i)
hasher := e.hashFunc()
- ctr := e.initCtr
- hashSize := hasher.Size()
- for i := 0; i < dataLength; i += hashSize {
- hasher.Write(key)
+ hasher.Write(e.key)
- ctrBytes := make([]byte, 4)
- binary.LittleEndian.PutUint32(ctrBytes, ctr)
+ ctrBytes := make([]byte, 4)
+ binary.LittleEndian.PutUint32(ctrBytes, uint32(i)+e.initCtr)
+ hasher.Write(ctrBytes)
- hasher.Write(ctrBytes)
+ ctrHash := hasher.Sum(nil)
+ hasher.Reset()
- ctrHash := hasher.Sum(nil)
- hasher.Reset()
- hasher.Write(ctrHash)
+ // second round of hashing for selective disclosure
+ hasher.Write(ctrHash)
+ segmentKey := hasher.Sum(nil)
+ hasher.Reset()
- segmentKey := hasher.Sum(nil)
-
- hasher.Reset()
+ // XOR bytes uptil length of in (out must be at least as long)
+ inLength := len(in)
+ for j := 0; j < inLength; j++ {
+ out[j] = in[j] ^ segmentKey[j]
+ }
+ // insert padding if out is longer
+ pad(out[inLength:])
+}
- segmentSize := min(hashSize, dataLength-i)
- for j := 0; j < segmentSize; j++ {
- transformedData[i+j] = data[i+j] ^ segmentKey[j]
- }
- ctr++
+func pad(b []byte) {
+ l := len(b)
+ for total := 0; total < l; {
+ read, _ := rand.Read(b[total:])
+ total += read
}
- return transformedData
}
-func GenerateRandomKey() (Key, error) {
- key := make([]byte, KeyLength)
- _, err := rand.Read(key)
- return key, err
+// GenerateRandomKey generates a random key of length l
+func GenerateRandomKey(l int) Key {
+ key := make([]byte, l)
+ var total int
+ for total < l {
+ read, _ := rand.Read(key[total:])
+ total += read
+ }
+ return key
}
func min(x, y int) int {
diff --git a/swarm/storage/encryption/encryption_test.go b/swarm/storage/encryption/encryption_test.go
index 5ea546d6b..c3abefdce 100644
--- a/swarm/storage/encryption/encryption_test.go
+++ b/swarm/storage/encryption/encryption_test.go
@@ -22,34 +22,42 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto/sha3"
)
-var expectedTransformedHex = "470c6c67ba1820d5cb4c23ccef22aa2417a323dc97e5f5dced930d74f2932fd178df80ddf129f4f8a4ccec0225c1c2e6765cbbd92bbad8413c50d93d53f7b2fec975d6f29468eccdaf6458f7a3306a7bc207211ea7f9ee5e6951ce6874aef09eb7ff9bed0aa00920b4dcc105e5f1f8dfbdb0564751311d6ceaca1e4e6d988097582638106404c03cfaef8db0e46674d9e8192c1b62d1cd952389cab3a8dee9329fdb059bafd9bae3df3a6b5a9a10961a0333016c99ee3d65cf18ea8ea7b4c386d59dcbf317460d517d5b55504b5992ffb9c3d7c49ebe1fe3ab7b00ad84b1d76d95f8165141260e6980b2ffe8a0000c36dd77ace4c7a781887f831f740d92d8b4848f1b9e237877b988b5a3e23d7b07b2c8eda0ea9fa748ab10bb6bfd7447b66f44e528d24eff31defdecddaf2bb5e6b8e2aa3d2f1a83de44e0ee3789b75dadba1375b7f3a8f7f1eb2d9b78ad1844d425fb76ea6ba45eabe88f1e062d7552d8c7d44c9c66c2753c41892cb675fd1d564b5f4746e76aa4b24ad121a907b8786715483067f46f1cd4a3dad5125f58c3d348db776e99e8a562ebe603e0e98509c72118ee81259b43f1f770dc9220dddbe4d12d2ffabdad76663d1cf30304eacbb43e9bbe0e4f95aae8609bf8a0786e56e0d20d4875d17cec644ca16824424c6c0700e5082ad5288d1a9fec637b75d24c270086a3606b97cc3240314ac123c04ff4d67ef547504f0eeea5e6252f9b5b75e47d32e583c4dee95ac84b6f03fef412e24c09697d6f7bc8408c2118c524f8e277b82658a5869d6d69d7fde469be27ea33fa22b47f3276f60580f2a05b0fbceb67949d2c8e6d8b097ceef6781d962866b23bc71b54597dd05caafbd533ff4e0013f0fc7e202782ba1e6ccd11242a5bc823af9ad0d5bcb8b78d0ce150fc6f8b97c66f9337adaf3878cbb70733044fd14f318d8e389940d07e0593e35f46dc84e7a9a75dadda153bbe5755af0683cfd262ce3797b1bc648a4e5cef5d9aa47d08cf78c6c9dd872096deb856680d5d932abfd5f2024f908ab84d19b762fdcd31209b1d9adf9cbab904bc58f5b00d5a3e0eb2ade52c7c9a678aadedb1b9257263e6145d34ebcc250d0867e2fdc2ed23b4a8e8aa580424308b543b76595f7e09127e8c301d3f6c228e656df2b5e63a89d634db2f87249025ad3b53d2703d6b93c4ab6b1dee4f9b4d2a0b383ed87458e0e1b2a3c04f9a08b885d856ea7ca9abda9a9c8bd28ecce78675b16829493dbeb66963a3665a8386bc4b97d13cfacacfa80b12e36b598d4f09ab7847481a95b35a937bd4f0107598844fc518c4134e8ca55cec024773dcf0a17c71f602406363dcc03912f23cffad9c611e34605fb03fea3d84aac33886efed6c53d455c786231436c01524cd41e2b6c35b339feaa94d7df0b3572db5595c05a1d4a96e1a17e814cea965be81786784af5697b5c7909fd7701d0f5d991f469e20fbc39536239c7a53278c0b1189253d3d978d54b51d33e0c8ac03ca1f08cfd440130944ae9d353b0b7f263a3a27d15290f35c0ad7cf62e8429ebfa10f5471987c53c5d574c9aebb935bdb8339fee9e1030b3f2845c36272642233afba71f81f10322057b51a33b434a4bc45530581c4a636895fc773e20cf6b8a6cef060920310f4cb79f735fc14e758f646b0cf3bf0ce1f1479788f5b73507203d54022c7afd805d46f45e7ede96b2660869939440d7d575fbf372a7f63421728343dfd88c5fa29ea3f15b68fe360f54afa0681093f2c82888d6babf9558159383c1a76264deec2d7fccb20dbd3ab4b3f137fb3dcf253fb6953df2f663d08e8b39909c9dbff98d49377ce0ce03c580b5e1bca6fcf58aceda42b00b1f478cff2995d47c82f2d5a3dc0e9718a0a46d8330353f2039e68d9565d29e77efea91e058ae03140a4b58b297ae664c9f0e7af78f3633f4aeabd95fd367ac5c67eb63fa2bd7035f4adfe3ab8502952d1675b47118b2006b4a5a1b2a3d03aa670862adc5f1ad1b39f0e4a08e2412128e0ef5fa84366b4b50992cc139e7837f8d65f8eae3c8dc2730f2ef1e1585ce95b0fe354c6c853526558a1732171b6017254ba0f0c22273b55caa2ee680791fb34e22bf897a0998156083c83d03310956b1f947ef474c90b2d7e20beae27f5d33b79ad6d9b1b0188e3cf850108f3a02f9386a314b97fb6c946e572e40024da3e4784c523cf2a70e45f6c0f8f35e9b279aecee183ccb30477ee4f5d57c246ab9918495159307935340a92bd46d6519bcc51af4a785a7eb7fa6eae9def89e2411efd2cb2c33f4d605b77af1ae298967fd846453e8b0a55c57706e79d7badd93268d93be27790bbb051496552b094f37bf96843cdf7604dc7f696976bebbe3561c7bd4b3f2843bd07e34a3c3acf0d6c755014a3e9d922dabdbc892511b6af3214958b3531baceab9082c2b4e19ef802b99db2cfa4076ba681efae8a9546582e4cbf07000fb3903727261b93d1bd08809ddc41b2a61b0bfa6b9210b8731394fd9084bc1406bcdd0992410e90f749a087edafb76f6617209855269bb5c89711d2830ea99f2a0e548991ef8dd3e62ced239dff4e9d8c1e834fb57078dc2a4322acc1ea1dbe64064db4cc2a7cdc32884cb7c31aa3c95634356b4d32f1c92fa039e5ed18c1af6605e2f66e5383fa1fcc610a3cc1eef5fe6296ac378f2440d0bd3c77d458af0bfa6b64cedd0301b116efafbbb8f9e88d4bedf56d11cfe0967fc06932e1f232c7daf2c73b58c52daa82dc22b2290147e358348f991f1473c4e63ac943cabc429f5689da8aee6801fd941778966da87fe137b033a0231a90a2ac759efbcb7c52de8e8f27bcc4e5bcb560524d17b0345727f8092e22b6a0e03ceee355085d4fe81568b5b8b84b69870dd333c9b3bdca45db7e43b876a217819928fec31f3ca4c44c4f03a91d578f9ed883bf1247a10eefe42279484af6f70719e193b07a14fc7d93fd6cee9e883a81cc51b53044fa2f1b2525c10e23fb988b31559e1fae4c082d905486d984d2f1e87c40976a571f92e4fdf09e23cad561d9cd3d1ca94e778d08b82852dbe9bab2c7f147c6078504c30fc3fe749fca95ed23791dcf6b935ab0ed08645c481cd2b7969258405f183593617c0d24ebe79bc6c87df65ddc25f933b12a641cc95cf321c1b2edf5db5813a98d99fd1760b5fac19c2b47c2a750e96da49c97276cf31cbd73e1e93ef6990fdf1b08a3e7963dffcf65aa6496727f6be5d9225cfbbadfd6a3a06a454acbb80e761699be97b9caeb71dc3c20a2c253f349ee190b9d8c1ff95751a281ed88b098e4a78fae8249232d4280daf46580ca6c14411f8c4d0e8fa44f8808a5a2dda36d35f79aa77c1c4c615216ec309aa5f3caff3a449b9740baad11e525a5651416a12dd4688897b5ee5e1e8361a87269e9be0789ea7564f64752788f3ac57bda4aa45582d8dabc4d44759639984514d9b151004bf0d9d3140becde41603ffd9d412ec08a1b2f7262862a761d7ce5b91a239d68cdfe7c615b62217422c5a224e652cffdbbe7b41064c9375bbf2c23b63130afedd93987c1f1e4a1623a77d3ef4960fd232afc7d12159c8f1245984e4bd390685668f10da77bf5f6130a5d405a42fb02d0048d63ca48cd4901f3704975b0493714c78de33c1a969993529bac13e310ee098a7b1e8e93b4fcb269773a1521defef98f403f79a8e24e1594b8dc6055223b79b4d7009498c02790a37dd3a9ac7168b11568877ee852395165f87d881355327e57ba48be948b1325824244a552ca80c2ecb79a04a199f0b6a58b455327d998a67ebae414394928161a311de9d3d7f1fc99c0bc35b0a814e7821d2d6958129775c56fdd9b28b6e43a3132a95eb64805f9941b0c5ca2078c37bc7a4d43ddcbc6e8c66de2ef51c714a81913bebeb8f9c6aa14da7e71854870fba9f093aa77abeb23e8d37f3a50135a3f894d1cdf647d3dceb3f16ad4b4f01dffe99d74cd1f18d37735ac69287df0a8b49b2fc3773bf426c881b64a1241c1143e39b6dca59e28c116947aac39585dd81f6fe3832f97d873884738982976f9f29aa6463662cc81c2abbd5eafbb3d9800ba811410a521065d61ad01cfde2c2d98f5fa0ec63e8b01ec6a2d738a1f6cf8c99725079aa51ed3dc7630deeea0b27ee8edbfa19bdb8504cf80a1ca74ea6777fa8786fd76d4ab019c00da35278bf49be5a42aff264875b69bab9e7f3f9299f2ea6a883fc5fd77e34debf414ce8af37a3e9a7de05f33bc547899d25a13389d9048be8b2b7c9b836b401eac9c53ba3d44a14e683a6b378248fdedcbfbc408e5ec83a6c3f769533ae90e339222d80d433ae820fca43d80bca7fbd9d6e5eb760271c74a95a35a853285f7dcfe10182af922508501d269cc53ed38756e8d202b25782ec208a39981ef6c9e9342eb6cee2142471574ab39ebdbbf140f64e305d6f6aa73d49d5bb765347a27ebd0ba1bdcaa8a383526b41f3361faddafec726e185cc223f8465472d7a53ad2d74717960ba5684bc692f773e680d0247f9de1650c046ea56fa18c1c3fb6636327f863f37dca86867c57cc643ff6b7973f97c91716502c33f0dc66176357315f09064c70df7db026413567ac9ec7605acd80606d962f7463359998b92f8a33ccffc80f6e162c1b5a65404e0cc4e37688ded910e6ae5f774e3238a1248b05c53486d149734dd1e38073603df0aa4a4f01fd0c1a0e82b6a513f7d22d1b09ff107923462fbfffbf5fb1f2c043e305917eee1f7f18f62dc604a1d39e5bf675dca67da52f95d312b31be7720efd391bf4794f0555b299325b5dfea9eb00e695861634ad28717cffff266e30c864ba844b0c3fd88bd0cee4d929530c2bb3663c5170a15a66c412ff2fed2d962dd0ff145f19f8085931cbd6bde4c11c9c2debfbdb6748d1a6dabf1404762343d468944a0495026091bc44c69dad971890b7221e1eac2e985097d344a4e2375938aa93806ad1715be8d05f4068ec67ef411e704b01851b7427c4137e6dadedfbb25378ecf1c6b749214f2655cf43fdbb72cb842aaab3074cd792f30f96e874d92f2ef62667d81ccd663dfd969c18dff790b6b7b261f0a03baa85bfd7db72baffe2ddc4cc3985183301a77daa826b1f76f6b6f2ac075c6a2b86609e4d26eb08f3ed6f341d7946966e654ed2c30a629ff81a57014a84105a9ad36a525033f16e3e60d639bf8f89ae6cfdbcdb41e93859354957dcfe9a847757c3cd946d8994cda126f146b77119bbc87c49ce79ad844715cd9bb0c7a4f800fce14c81d175aed59fce0377e62c6e597ab5acf1b3b7100403f371c19dd0f131c4c572e57e3e13743f9bac24a6a177d71f03c5d185bb7e163ec5866dda629340a964bc442d423ad7bc5187f3da68d1498dfe9f1815b31bae11df3585ece230cc3521f7a0b4b3360ddf898984b528afff75f229915f1f2d5c4491c65e2f38d26c0de7dc483860da7bf52859fdbc21946badec0bbf00ba8143b8b7289cfb7096d3405e3183e56f1cbb8c48f25d058530894d0302cdce7c43ea31768b5b610820c97f6e9a8e31a8e9c4624117d213a03ef7d655513cffd8fb5606fc8790692c99828a47382e3e37b9c1317028f5c9d196ff3c2f09435df7614fb37ea20b2371c52b6c4667799922010edeb28001de2a137889db4d3dbf0a406ba90f3631be485ec5e4110b01502f557f15026716030fb6384499adee3cfc44015638e05b206ce3cbc3cbf21b7dd1dcb3b932629e7cd4f4f6b148f37f976803644e5ce792583daf39608a3cd02ff2f47e9bc6"
+var expectedTransformedHex = "352187af3a843decc63ceca6cb01ea39dbcf77caf0a8f705f5c30d557044ceec9392b94a79376f1e5c10cd0c0f2a98e5353bf22b3ea4fdac6677ee553dec192e3db64e179d0474e96088fb4abd2babd67de123fb398bdf84d818f7bda2c1ab60b3ea0e0569ae54aa969658eb4844e6960d2ff44d7c087ee3aaffa1c0ee5df7e50b615f7ad90190f022934ad5300c7d1809bfe71a11cc04cece5274eb97a5f20350630522c1dbb7cebaf4f97f84e03f5cfd88f2b48880b25d12f4d5e75c150f704ef6b46c72e07db2b705ac3644569dccd22fd8f964f6ef787fda63c46759af334e6f665f70eac775a7017acea49f3c7696151cb1b9434fa4ac27fb803921ffb5ec58dafa168098d7d5b97e384be3384cf5bc235c3d887fef89fe76c0065f9b8d6ad837b442340d9e797b46ef5709ea3358bc415df11e4830de986ef0f1c418ffdcc80e9a3cda9bea0ab5676c0d4240465c43ba527e3b4ea50b4f6255b510e5d25774a75449b0bd71e56c537ade4fcf0f4d63c99ae1dbb5a844971e2c19941b8facfcfc8ee3056e7cb3c7114c5357e845b52f7103cb6e00d2308c37b12baa5b769e1cc7b00fc06f2d16e70cc27a82cb9c1a4e40cb0d43907f73df2c9db44f1b51a6b0bc6d09f77ac3be14041fae3f9df2da42df43ae110904f9ecee278030185254d7c6e918a5512024d047f77a992088cb3190a6587aa54d0c7231c1cd2e455e0d4c07f74bece68e29cd8ba0190c0bcfb26d24634af5d91a81ef5d4dd3d614836ce942ddbf7bb1399317f4c03faa675f325f18324bf9433844bfe5c4cc04130c8d5c329562b7cd66e72f7355de8f5375a72202971613c32bd7f3fcdcd51080758cd1d0a46dbe8f0374381dbc359f5864250c63dde8131cbd7c98ae2b0147d6ea4bf65d1443d511b18e6d608bbb46ac036353b4c51df306a10a6f6939c38629a5c18aaf89cac04bd3ad5156e6b92011c88341cb08551bab0a89e6a46538f5af33b86121dba17e3a434c273f385cd2e8cb90bdd32747d8425d929ccbd9b0815c73325988855549a8489dfd047daf777aaa3099e54cf997175a5d9e1edfe363e3b68c70e02f6bf4fcde6a0f3f7d0e7e98bde1a72ae8b6cd27b32990680cc4a04fc467f41c5adcaddabfc71928a3f6872c360c1d765260690dd28b269864c8e380d9c92ef6b89b0094c8f9bb22608b4156381b19b920e9583c9616ce5693b4d2a6c689f02e6a91584a8e501e107403d2689dd0045269dd9946c0e969fb656a3b39d84a798831f5f9290f163eb2f97d3ae25071324e95e2256d9c1e56eb83c26397855323edc202d56ad05894333b7f0ed3c1e4734782eb8bd5477242fd80d7a89b12866f85cfae476322f032465d6b1253993033fccd4723530630ab97a1566460af9c90c9da843c229406e65f3fa578bd6bf04dee9b6153807ddadb8ceefc5c601a8ab26023c67b1ab1e8e0f29ce94c78c308005a781853e7a2e0e51738939a657c987b5e611f32f47b5ff461c52e63e0ea390515a8e1f5393dae54ea526934b5f310b76e3fa050e40718cb4c8a20e58946d6ee1879f08c52764422fe542b3240e75eccb7aa75b1f8a651e37a3bc56b0932cdae0e985948468db1f98eb4b77b82081ea25d8a762db00f7898864984bd80e2f3f35f236bf57291dec28f550769943bcfb6f884b7687589b673642ef7fe5d7d5a87d3eca5017f83ccb9a3310520474479464cb3f433440e7e2f1e28c0aef700a45848573409e7ab66e0cfd4fe5d2147ace81bc65fd8891f6245cd69246bbf5c27830e5ab882dd1d02aba34ff6ca9af88df00fd602892f02fedbdc65dedec203faf3f8ff4a97314e0ddb58b9ab756a61a562597f4088b445fcc3b28a708ca7b1485dcd791b779fbf2b3ef1ec5c6205f595fbe45a02105034147e5a146089c200a49dae33ae051a08ea5f974a21540aaeffa7f9d9e3d35478016fb27b871036eb27217a5b834b461f535752fb5f1c8dded3ae14ce3a2ef6639e2fe41939e3509e46e347a95d50b2080f1ba42c804b290ddc912c952d1cec3f2661369f738feacc0dbf1ea27429c644e45f9e26f30c341acd34c7519b2a1663e334621691e810767e9918c2c547b2e23cce915f97d26aac8d0d2fcd3edb7986ad4e2b8a852edebad534cb6c0e9f0797d3563e5409d7e068e48356c67ce519246cd9c560e881453df97cbba562018811e6cf8c327f399d1d1253ab47a19f4a0ccc7c6d86a9603e0551da310ea595d71305c4aad96819120a92cdbaf1f77ec8df9cc7c838c0d4de1e8692dd81da38268d1d71324bcffdafbe5122e4b81828e021e936d83ae8021eac592aa52cd296b5ce392c7173d622f8e07d18f59bb1b08ba15211af6703463b09b593af3c37735296816d9f2e7a369354a5374ea3955e14ca8ac56d5bfe4aef7a21bd825d6ae85530bee5d2aaaa4914981b3dfdb2e92ec2a27c83d74b59e84ff5c056f7d8945745f2efc3dcf28f288c6cd8383700fb2312f7001f24dd40015e436ae23e052fe9070ea9535b9c989898a9bda3d5382cf10e432fae6ccf0c825b3e6436edd3a9f8846e5606f8563931b5f29ba407c5236e5730225dda211a8504ec1817bc935e1fd9a532b648c502df302ed2063aed008fd5676131ac9e95998e9447b02bd29d77e38fcfd2959f2de929b31970335eb2a74348cc6918bc35b9bf749eab0fe304c946cd9e1ca284e6853c42646e60b6b39e0d3fb3c260abfc5c1b4ca3c3770f344118ca7c7f5c1ad1f123f8f369cd60afc3cdb3e9e81968c5c9fa7c8b014ffe0508dd4f0a2a976d5d1ca8fc9ad7a237d92cfe7b41413d934d6e142824b252699397e48e4bac4e91ebc10602720684bd0863773c548f9a2f9724245e47b129ecf65afd7252aac48c8a8d6fd3d888af592a01fb02dc71ed7538a700d3d16243e4621e0fcf9f8ed2b4e11c9fa9a95338bb1dac74a7d9bc4eb8cbf900b634a2a56469c00f5994e4f0934bdb947640e6d67e47d0b621aacd632bfd3c800bd7d93bd329f494a90e06ed51535831bd6e07ac1b4b11434ef3918fa9511813a002913f33f836454798b8d1787fea9a4c4743ba091ed192ed92f4d33e43a226bf9503e1a83a16dd340b3cbbf38af6db0d99201da8de529b4225f3d2fa2aad6621afc6c79ef3537720591edfc681ae6d00ede53ed724fc71b23b90d2e9b7158aaee98d626a4fe029107df2cb5f90147e07ebe423b1519d848af18af365c71bfd0665db46be493bbe99b79a188de0cf3594aef2299f0324075bdce9eb0b87bc29d62401ba4fd6ae48b1ba33261b5b845279becf38ee03e3dc5c45303321c5fac96fd02a3ad8c9e3b02127b320501333c9e6360440d1ad5e64a6239501502dde1a49c9abe33b66098458eee3d611bb06ffcd234a1b9aef4af5021cd61f0de6789f822ee116b5078aae8c129e8391d8987500d322b58edd1595dc570b57341f2df221b94a96ab7fbcf32a8ca9684196455694024623d7ed49f7d66e8dd453c0bae50e0d8b34377b22d0ece059e2c385dfc70b9089fcd27577c51f4d870b5738ee2b68c361a67809c105c7848b68860a829f29930857a9f9d40b14fd2384ac43bafdf43c0661103794c4bd07d1cfdd4681b6aeaefad53d4c1473359bcc5a83b09189352e5bb9a7498dd0effb89c35aad26954551f8b0621374b449bf515630bd3974dca982279733470fdd059aa9c3df403d8f22b38c4709c82d8f12b888e22990350490e16179caf406293cc9e65f116bafcbe96af132f679877061107a2f690a82a8cb46eea57a90abd23798c5937c6fe6b17be3f9bfa01ce117d2c268181b9095bf49f395fea07ca03838de0588c5e2db633e836d64488c1421e653ea52d810d096048c092d0da6e02fa6613890219f51a76148c8588c2487b171a28f17b7a299204874af0131725d793481333be5f08e86ca837a226850b0c1060891603bfecf9e55cddd22c0dbb28d495342d9cc3de8409f72e52a0115141cffe755c74f061c1a770428ccb0ae59536ee6fc074fbfc6cacb51a549d327527e20f8407477e60355863f1153f9ce95641198663c968874e7fdb29407bd771d94fdda8180cbb0358f5874738db705924b8cbe0cd5e1484aeb64542fe8f38667b7c34baf818c63b1e18440e9fba575254d063fd49f24ef26432f4eb323f3836972dca87473e3e9bb26dc3be236c3aae6bc8a6da567442309da0e8450e242fc9db836e2964f2c76a3b80a2c677979882dda7d7ebf62c93664018bcf4ec431fe6b403d49b3b36618b9c07c2d0d4569cb8d52223903debc72ec113955b206c34f1ae5300990ccfc0180f47d91afdb542b6312d12aeff7e19c645dc0b9fe6e3288e9539f6d5870f99882df187bfa6d24d179dfd1dac22212c8b5339f7171a3efc15b760fed8f68538bc5cbd845c2d1ab41f3a6c692820653eaef7930c02fbe6061d93805d73decdbb945572a7c44ed0241982a6e4d2d730898f82b3d9877cb7bca41cc6dcee67aa0c3d6db76f0b0a708ace0031113e48429de5d886c10e9200f68f32263a2fbf44a5992c2459fda7b8796ba796e3a0804fc25992ed2c9a5fe0580a6b809200ecde6caa0364b58be11564dcb9a616766dd7906db5636ee708b0204f38d309466d8d4a162965dd727e29f5a6c133e9b4ed5bafe803e479f9b2a7640c942c4a40b14ac7dc9828546052761a070f6404008f1ec3605836339c3da95a00b4fd81b2cabf88b51d2087d5b83e8c5b69bf96d8c72cbd278dad3bbb42b404b436f84ad688a22948adf60a81090f1e904291503c16e9f54b05fc76c881a5f95f0e732949e95d3f1bae2d3652a14fe0dda2d68879604657171856ef72637def2a96ac47d7b3fe86eb3198f5e0e626f06be86232305f2ae79ffcd2725e48208f9d8d63523f81915acc957563ab627cd6bc68c2a37d59fb0ed77a90aa9d085d6914a8ebada22a2c2d471b5163aeddd799d90fbb10ed6851ace2c4af504b7d572686700a59d6db46d5e42bb83f8e0c0ffe1dfa6582cc0b34c921ff6e85e83188d24906d5c08bb90069639e713051b3102b53e6f703e8210017878add5df68e6f2b108de279c5490e9eef5590185c4a1c744d4e00d244e1245a8805bd30407b1bc488db44870ccfd75a8af104df78efa2fb7ba31f048a263efdb3b63271fff4922bece9a71187108f65744a24f4947dc556b7440cb4fa45d296bb7f724588d1f245125b21ea063500029bd49650237f53899daf1312809552c81c5827341263cc807a29fe84746170cdfa1ff3838399a5645319bcaff674bb70efccdd88b3d3bb2f2d98111413585dc5d5bd5168f43b3f55e58972a5b2b9b3733febf02f931bd436648cb617c3794841aab961fe41277ab07812e1d3bc4ff6f4350a3e615bfba08c3b9480ef57904d3a16f7e916345202e3f93d11f7a7305170cb8c4eb9ac88ace8bbd1f377bdd5855d3162d6723d4435e84ce529b8f276a8927915ac759a0d04e5ca4a9d3da6291f0333b475df527e99fe38f7a4082662e8125936640c26dd1d17cf284ce6e2b17777a05aa0574f7793a6a062cc6f7263f7ab126b4528a17becfdec49ac0f7d8705aa1704af97fb861faa8a466161b2b5c08a5bacc79fe8500b913d65c8d3c52d1fd52d2ab2c9f52196e712455619c1cd3e0f391b274487944240e2ed8858dd0823c801094310024ae3fe4dd1cf5a2b6487b42cc5937bbafb193ee331d87e378258963d49b9da90899bbb4b88e79f78e866b0213f4719f67da7bcc2fce073c01e87c62ea3cdbcd589cfc41281f2f4c757c742d6d1e"
var hashFunc = sha3.NewKeccak256
+var testKey Key
+
+func init() {
+ var err error
+ testKey, err = hexutil.Decode("0x8abf1502f557f15026716030fb6384792583daf39608a3cd02ff2f47e9bc6e49")
+ if err != nil {
+ panic(err.Error())
+ }
+}
func TestEncryptDataLongerThanPadding(t *testing.T) {
- enc := New(4095, uint32(0), hashFunc)
+ enc := New(testKey, 4095, uint32(0), hashFunc)
data := make([]byte, 4096)
- key := make([]byte, 32)
expectedError := "Data length longer than padding, data length 4096 padding 4095"
- _, err := enc.Encrypt(data, key)
+ _, err := enc.Encrypt(data)
if err == nil || err.Error() != expectedError {
t.Fatalf("Expected error \"%v\" got \"%v\"", expectedError, err)
}
}
func TestEncryptDataZeroPadding(t *testing.T) {
- enc := New(0, uint32(0), hashFunc)
+ enc := New(testKey, 0, uint32(0), hashFunc)
data := make([]byte, 2048)
- key := make([]byte, 32)
- encrypted, err := enc.Encrypt(data, key)
+ encrypted, err := enc.Encrypt(data)
if err != nil {
t.Fatalf("Expected no error got %v", err)
}
@@ -59,12 +67,11 @@ func TestEncryptDataZeroPadding(t *testing.T) {
}
func TestEncryptDataLengthEqualsPadding(t *testing.T) {
- enc := New(4096, uint32(0), hashFunc)
+ enc := New(testKey, 4096, uint32(0), hashFunc)
data := make([]byte, 4096)
- key := make([]byte, 32)
- encrypted, err := enc.Encrypt(data, key)
+ encrypted, err := enc.Encrypt(data)
if err != nil {
t.Fatalf("Expected no error got %v", err)
}
@@ -77,12 +84,11 @@ func TestEncryptDataLengthEqualsPadding(t *testing.T) {
}
func TestEncryptDataLengthSmallerThanPadding(t *testing.T) {
- enc := New(4096, uint32(0), hashFunc)
+ enc := New(testKey, 4096, uint32(0), hashFunc)
data := make([]byte, 4080)
- key := make([]byte, 32)
- encrypted, err := enc.Encrypt(data, key)
+ encrypted, err := enc.Encrypt(data)
if err != nil {
t.Fatalf("Expected no error got %v", err)
}
@@ -96,14 +102,13 @@ func TestEncryptDataCounterNonZero(t *testing.T) {
}
func TestDecryptDataLengthNotEqualsPadding(t *testing.T) {
- enc := New(4096, uint32(0), hashFunc)
+ enc := New(testKey, 4096, uint32(0), hashFunc)
data := make([]byte, 4097)
- key := make([]byte, 32)
expectedError := "Data length different than padding, data length 4097 padding 4096"
- _, err := enc.Decrypt(data, key)
+ _, err := enc.Decrypt(data)
if err == nil || err.Error() != expectedError {
t.Fatalf("Expected error \"%v\" got \"%v\"", expectedError, err)
}
@@ -117,20 +122,18 @@ func TestEncryptDecryptIsIdentity(t *testing.T) {
}
func testEncryptDecryptIsIdentity(t *testing.T, padding int, initCtr uint32, dataLength int, keyLength int) {
- enc := New(padding, initCtr, hashFunc)
+ key := GenerateRandomKey(keyLength)
+ enc := New(key, padding, initCtr, hashFunc)
data := make([]byte, dataLength)
rand.Read(data)
- key := make([]byte, keyLength)
- rand.Read(key)
-
- encrypted, err := enc.Encrypt(data, key)
+ encrypted, err := enc.Encrypt(data)
if err != nil {
t.Fatalf("Expected no error got %v", err)
}
- decrypted, err := enc.Decrypt(encrypted, key)
+ decrypted, err := enc.Decrypt(encrypted)
if err != nil {
t.Fatalf("Expected no error got %v", err)
}
diff --git a/swarm/storage/hasherstore.go b/swarm/storage/hasherstore.go
index bc23077c1..766207eae 100644
--- a/swarm/storage/hasherstore.go
+++ b/swarm/storage/hasherstore.go
@@ -26,49 +26,34 @@ import (
"github.com/ethereum/go-ethereum/swarm/storage/encryption"
)
-type chunkEncryption struct {
- spanEncryption encryption.Encryption
- dataEncryption encryption.Encryption
-}
-
type hasherStore struct {
- store ChunkStore
- hashFunc SwarmHasher
- chunkEncryption *chunkEncryption
- hashSize int // content hash size
- refSize int64 // reference size (content hash + possibly encryption key)
- wg *sync.WaitGroup
- closed chan struct{}
-}
-
-func newChunkEncryption(chunkSize, refSize int64) *chunkEncryption {
- return &chunkEncryption{
- spanEncryption: encryption.New(0, uint32(chunkSize/refSize), sha3.NewKeccak256),
- dataEncryption: encryption.New(int(chunkSize), 0, sha3.NewKeccak256),
- }
+ store ChunkStore
+ toEncrypt bool
+ hashFunc SwarmHasher
+ hashSize int // content hash size
+ refSize int64 // reference size (content hash + possibly encryption key)
+ wg *sync.WaitGroup
+ closed chan struct{}
}
// NewHasherStore creates a hasherStore object, which implements Putter and Getter interfaces.
// With the HasherStore you can put and get chunk data (which is just []byte) into a ChunkStore
// and the hasherStore will take core of encryption/decryption of data if necessary
func NewHasherStore(chunkStore ChunkStore, hashFunc SwarmHasher, toEncrypt bool) *hasherStore {
- var chunkEncryption *chunkEncryption
-
hashSize := hashFunc().Size()
refSize := int64(hashSize)
if toEncrypt {
refSize += encryption.KeyLength
- chunkEncryption = newChunkEncryption(chunk.DefaultSize, refSize)
}
return &hasherStore{
- store: chunkStore,
- hashFunc: hashFunc,
- chunkEncryption: chunkEncryption,
- hashSize: hashSize,
- refSize: refSize,
- wg: &sync.WaitGroup{},
- closed: make(chan struct{}),
+ store: chunkStore,
+ toEncrypt: toEncrypt,
+ hashFunc: hashFunc,
+ hashSize: hashSize,
+ refSize: refSize,
+ wg: &sync.WaitGroup{},
+ closed: make(chan struct{}),
}
}
@@ -79,7 +64,7 @@ func (h *hasherStore) Put(ctx context.Context, chunkData ChunkData) (Reference,
c := chunkData
size := chunkData.Size()
var encryptionKey encryption.Key
- if h.chunkEncryption != nil {
+ if h.toEncrypt {
var err error
c, encryptionKey, err = h.encryptChunkData(chunkData)
if err != nil {
@@ -155,23 +140,14 @@ func (h *hasherStore) encryptChunkData(chunkData ChunkData) (ChunkData, encrypti
return nil, nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData))
}
- encryptionKey, err := encryption.GenerateRandomKey()
- if err != nil {
- return nil, nil, err
- }
-
- encryptedSpan, err := h.chunkEncryption.spanEncryption.Encrypt(chunkData[:8], encryptionKey)
- if err != nil {
- return nil, nil, err
- }
- encryptedData, err := h.chunkEncryption.dataEncryption.Encrypt(chunkData[8:], encryptionKey)
+ key, encryptedSpan, encryptedData, err := h.encrypt(chunkData)
if err != nil {
return nil, nil, err
}
c := make(ChunkData, len(encryptedSpan)+len(encryptedData))
copy(c[:8], encryptedSpan)
copy(c[8:], encryptedData)
- return c, encryptionKey, nil
+ return c, key, nil
}
func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryption.Key) (ChunkData, error) {
@@ -179,12 +155,7 @@ func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryp
return nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData))
}
- decryptedSpan, err := h.chunkEncryption.spanEncryption.Decrypt(chunkData[:8], encryptionKey)
- if err != nil {
- return nil, err
- }
-
- decryptedData, err := h.chunkEncryption.dataEncryption.Decrypt(chunkData[8:], encryptionKey)
+ decryptedSpan, decryptedData, err := h.decrypt(chunkData, encryptionKey)
if err != nil {
return nil, err
}
@@ -201,13 +172,46 @@ func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryp
copy(c[:8], decryptedSpan)
copy(c[8:], decryptedData[:length])
- return c[:length+8], nil
+ return c, nil
}
func (h *hasherStore) RefSize() int64 {
return h.refSize
}
+func (h *hasherStore) encrypt(chunkData ChunkData) (encryption.Key, []byte, []byte, error) {
+ key := encryption.GenerateRandomKey(encryption.KeyLength)
+ encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8])
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:])
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ return key, encryptedSpan, encryptedData, nil
+}
+
+func (h *hasherStore) decrypt(chunkData ChunkData, key encryption.Key) ([]byte, []byte, error) {
+ encryptedSpan, err := h.newSpanEncryption(key).Encrypt(chunkData[:8])
+ if err != nil {
+ return nil, nil, err
+ }
+ encryptedData, err := h.newDataEncryption(key).Encrypt(chunkData[8:])
+ if err != nil {
+ return nil, nil, err
+ }
+ return encryptedSpan, encryptedData, nil
+}
+
+func (h *hasherStore) newSpanEncryption(key encryption.Key) encryption.Encryption {
+ return encryption.New(key, 0, uint32(chunk.DefaultSize/h.refSize), sha3.NewKeccak256)
+}
+
+func (h *hasherStore) newDataEncryption(key encryption.Key) encryption.Encryption {
+ return encryption.New(key, int(chunk.DefaultSize), 0, sha3.NewKeccak256)
+}
+
func (h *hasherStore) storeChunk(ctx context.Context, chunk *Chunk) {
h.wg.Add(1)
go func() {