1// Copyright (C) 2021 Storj Labs, Inc.
2// See LICENSE for copying information.
3
4package encryption
5
6import (
7	"github.com/zeebo/errs"
8
9	"storj.io/common/paths"
10	"storj.io/common/storj"
11)
12
13// PrefixInfo is a helper type that contains all of the encrypted and unencrypted paths related
14// to some path and its parent. It includes the cipher that was used to encrypt and decrypt
15// the paths and what bucket it is in.
16type PrefixInfo struct {
17	Bucket string
18	Cipher storj.CipherSuite
19
20	PathUnenc paths.Unencrypted
21	PathEnc   paths.Encrypted
22	PathKey   storj.Key
23
24	ParentUnenc paths.Unencrypted
25	ParentEnc   paths.Encrypted
26	ParentKey   storj.Key
27}
28
29// GetPrefixInfo returns the PrefixInfo for some unencrypted path inside of a bucket.
30func GetPrefixInfo(bucket string, path paths.Unencrypted, store *Store) (pi *PrefixInfo, err error) {
31	_, remaining, base := store.LookupUnencrypted(bucket, path)
32	if base == nil {
33		return nil, ErrMissingEncryptionBase.New("%q/%q", bucket, path)
34	}
35
36	if path.Valid() && remaining.Done() {
37		return nil, ErrMissingEncryptionBase.New("no parent: %q/%q", bucket, path)
38	}
39
40	// if we're using the default base (meaning the default key), we need
41	// to include the bucket name in the path derivation.
42	key := &base.Key
43	if base.Default {
44		key, err = derivePathKeyComponent(key, bucket)
45		if err != nil {
46			return nil, errs.Wrap(err)
47		}
48	}
49
50	var (
51		pathUnenc   pathBuilder
52		pathEnc     pathBuilder
53		parentUnenc pathBuilder
54		parentEnc   pathBuilder
55	)
56
57	pathKey := *key
58	parentKey := *key
59
60	if !base.Default && base.Encrypted.Valid() {
61		pathUnenc.append(base.Unencrypted.Raw())
62		pathEnc.append(base.Encrypted.Raw())
63		parentUnenc.append(base.Unencrypted.Raw())
64		parentEnc.append(base.Encrypted.Raw())
65	}
66
67	var componentUnenc string
68	var componentEnc string
69
70	for i := 0; !remaining.Done(); i++ {
71		if i > 0 {
72			parentKey = *key
73			parentEnc.append(componentEnc)
74			parentUnenc.append(componentUnenc)
75		}
76
77		componentUnenc = remaining.Next()
78
79		componentEnc, err = encryptPathComponent(componentUnenc, base.PathCipher, key)
80		if err != nil {
81			return nil, errs.Wrap(err)
82		}
83		key, err = derivePathKeyComponent(key, componentUnenc)
84		if err != nil {
85			return nil, errs.Wrap(err)
86		}
87
88		pathKey = *key
89		pathUnenc.append(componentUnenc)
90		pathEnc.append(componentEnc)
91	}
92
93	return &PrefixInfo{
94		Bucket: bucket,
95		Cipher: base.PathCipher,
96
97		PathKey:   pathKey,
98		PathUnenc: pathUnenc.Unencrypted(),
99		PathEnc:   pathEnc.Encrypted(),
100
101		ParentKey:   parentKey,
102		ParentUnenc: parentUnenc.Unencrypted(),
103		ParentEnc:   parentEnc.Encrypted(),
104	}, nil
105}
106