encryption

package
v0.0.0-...-f34d2f5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2024 License: MIT Imports: 22 Imported by: 17

Documentation

Overview

Package encryption collects common cryptographic primitives needed for path and data encryption.

Index

Examples

Constants

View Source
const (
	// AESGCMNonceSize is the size of an AES-GCM nonce.
	AESGCMNonceSize = 12
)

Variables

View Source
var (

	// ErrMissingEncryptionBase is caused by trying to encrypt a path without
	// having the appropriate root in the encryption store.
	ErrMissingEncryptionBase = errs.Class("missing encryption base")

	// ErrMissingDecryptionBase is caused by trying to decrypt a path without
	// having the appropriate root in the encryption store.
	ErrMissingDecryptionBase = errs.Class("missing decryption base")
)
View Source
var ErrDecryptFailed = errs.Class("decryption failed, check encryption key")

ErrDecryptFailed is the errs class when the decryption fails.

View Source
var ErrInvalidConfig = errs.Class("invalid encryption configuration")

ErrInvalidConfig is the errs class for invalid configuration.

View Source
var Error = errs.Class("encryption")

Error is the default encryption errs class.

Functions

func CalcEncompassingBlocks

func CalcEncompassingBlocks(offset, length int64, blockSize int) (
	firstBlock, blockCount int64)

CalcEncompassingBlocks is a useful helper function that, given an offset, length, and blockSize, will tell you which blocks contain the requested offset and length.

func CalcEncryptedSize

func CalcEncryptedSize(dataSize int64, parameters storj.EncryptionParameters) (int64, error)

CalcEncryptedSize calculates what would be the size of the cipher data after encrypting data with dataSize using a Transformer with the given encryption parameters.

func CalcTransformerEncryptedSize

func CalcTransformerEncryptedSize(dataSize int64, transformer Transformer) int64

CalcTransformerEncryptedSize calculates what would be the size of the cipher data after encrypting data with dataSize using the given Transformer.

func Decrypt

func Decrypt(cipherData []byte, cipher storj.CipherSuite, key *storj.Key, nonce *storj.Nonce) (data []byte, err error)

Decrypt decrypts cipherData with the given cipher, key and nonce.

func DecryptAESGCM

func DecryptAESGCM(cipherData []byte, key *storj.Key, nonce *AESGCMNonce) (data []byte, err error)

DecryptAESGCM decrypts byte data with a key and nonce. It returns the plain data.

func DecryptIterator

func DecryptIterator(iter paths.Iterator, cipher storj.CipherSuite, key *storj.Key) (string, error)

DecryptIterator decrypts the iterator using the provided key directly, returning the joined path. DecryptPath should be preferred if possible.

func DecryptKey

func DecryptKey(keyToDecrypt storj.EncryptedPrivateKey, cipher storj.CipherSuite, key *storj.Key, nonce *storj.Nonce) (*storj.Key, error)

DecryptKey decrypts keyToDecrypt with the given cipher, key and nonce.

func DecryptPath

func DecryptPath(bucket string, path paths.Encrypted, pathCipher storj.CipherSuite, store *Store) (
	encPath paths.Unencrypted, err error)

DecryptPath decrypts the path using the provided cipher and looking up keys from the provided store and bucket.

func DecryptPathRaw

func DecryptPathRaw(raw string, cipher storj.CipherSuite, key *storj.Key) (string, error)

DecryptPathRaw decrypts the path using the provided key directly. DecryptPath should be preferred if possible.

func DecryptPathWithStoreCipher

func DecryptPathWithStoreCipher(bucket string, path paths.Encrypted, store *Store) (
	encPath paths.Unencrypted, err error)

DecryptPathWithStoreCipher decrypts the path looking up keys and the cipher from the provided store and bucket.

func DecryptSecretBox

func DecryptSecretBox(cipherData []byte, key *storj.Key, nonce *storj.Nonce) (data []byte, err error)

DecryptSecretBox decrypts byte data with a key and nonce. The plain data is returned.

func DeriveContentKey

func DeriveContentKey(bucket string, path paths.Unencrypted, store *Store) (key *storj.Key, err error)

DeriveContentKey returns the content key for the passed in path by looking up the appropriate base key from the store and bucket and deriving the rest.

func DeriveKey

func DeriveKey(key *storj.Key, message string) (*storj.Key, error)

DeriveKey derives new key from the given key and message using HMAC-SHA512.

func DerivePathKey

func DerivePathKey(bucket string, path paths.Unencrypted, store *Store) (key *storj.Key, err error)

DerivePathKey returns the path key for the passed in path by looking up the appropriate base key from the store and bucket and deriving the rest.

func DeriveRootKey

func DeriveRootKey(password, salt []byte, path storj.Path, argon2Threads uint8) (*storj.Key, error)

DeriveRootKey derives a root key for some path using the salt for the bucket and a password from the user. See the password key derivation design doc.

func Encrypt

func Encrypt(data []byte, cipher storj.CipherSuite, key *storj.Key, nonce *storj.Nonce) (cipherData []byte, err error)

Encrypt encrypts data with the given cipher, key and nonce.

func EncryptAESGCM

func EncryptAESGCM(data []byte, key *storj.Key, nonce *AESGCMNonce) (cipherData []byte, err error)

EncryptAESGCM encrypts byte data with a key and nonce. It returns the cipher data.

func EncryptIterator

func EncryptIterator(iter paths.Iterator, cipher storj.CipherSuite, key *storj.Key) (string, error)

EncryptIterator encrypts the iterator using the provided key directly, returning the joined path. EncryptPath should be preferred if possible.

func EncryptKey

func EncryptKey(keyToEncrypt *storj.Key, cipher storj.CipherSuite, key *storj.Key, nonce *storj.Nonce) (storj.EncryptedPrivateKey, error)

EncryptKey encrypts keyToEncrypt with the given cipher, key and nonce.

func EncryptPath

func EncryptPath(bucket string, path paths.Unencrypted, pathCipher storj.CipherSuite, store *Store) (
	encPath paths.Encrypted, err error)

EncryptPath encrypts the path using the provided cipher and looking up keys from the provided store and bucket.

Example
package main

import (
	"encoding/hex"
	"fmt"

	"storj.io/common/encryption"
	"storj.io/common/paths"
	"storj.io/common/storj"
)

func main() {
	path := paths.NewUnencrypted("fold1/fold2/fold3/file.txt")

	// seed
	seed := new(storj.Key)
	for i := range seed {
		seed[i] = byte(i)
	}
	fmt.Printf("root key (%d bytes): %s\n", len(seed), hex.EncodeToString(seed[:]))

	store := encryption.NewStore()
	store.SetDefaultKey(seed)
	store.SetDefaultPathCipher(storj.EncAESGCM)

	// use the seed for encrypting the path
	encryptedPath, err := encryption.EncryptPathWithStoreCipher("bucket", path, store)
	if err != nil {
		panic(err)
	}
	fmt.Println("path to encrypt:", path)
	fmt.Println("encrypted path: ", hex.EncodeToString([]byte(encryptedPath.Raw())))

	// decrypting the path
	decryptedPath, err := encryption.DecryptPathWithStoreCipher("bucket", encryptedPath, store)
	if err != nil {
		panic(err)
	}
	fmt.Println("decrypted path: ", decryptedPath)

}
Output:

root key (32 bytes): 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
path to encrypt: fold1/fold2/fold3/file.txt
encrypted path:  02387ce34e2054bcb9a0428b820102876eef8325a8397bf7568e91afc40739406ffad12f02453d291b9cb8947155462d6c1edc2367507b0de55b46fa7231f3ba6ad7ce79f4822f02ad7257e8ef4f938ac6b6794b50852873d1b3d32e018dfb17a674dc806ac6e8ddd4262f02aa2128dc8614940f7cf6628513b581f7c18724af3c01018f7c861520c2fdfd78f7b1b25ce0
decrypted path:  fold1/fold2/fold3/file.txt

func EncryptPathRaw

func EncryptPathRaw(raw string, cipher storj.CipherSuite, key *storj.Key) (string, error)

EncryptPathRaw encrypts the path using the provided key directly. EncryptPath should be preferred if possible.

func EncryptPathWithStoreCipher

func EncryptPathWithStoreCipher(bucket string, path paths.Unencrypted, store *Store) (
	encPath paths.Encrypted, err error)

EncryptPathWithStoreCipher encrypts the path looking up keys and the cipher from the provided store and bucket.

func EncryptPrefixWithStoreCipher

func EncryptPrefixWithStoreCipher(bucket string, path paths.Unencrypted, store *Store) (
	encPath paths.Encrypted, err error)

EncryptPrefixWithStoreCipher encrypts the prefix using the provided cipher and looking up keys from the provided store and bucket. Because it is a prefix, it does not assume there is an empty component at the end of a path like "foo/bar/".

func EncryptSecretBox

func EncryptSecretBox(data []byte, key *storj.Key, nonce *storj.Nonce) (cipherData []byte, err error)

EncryptSecretBox encrypts byte data with a key and nonce. The cipher data is returned.

func Increment

func Increment(nonce *storj.Nonce, amount int64) (truncated bool, err error)

Increment increments the nonce with the given amount.

func Pad

func Pad(data ranger.Ranger, blockSize int) (
	rr ranger.Ranger, padding int)

Pad takes a Ranger and returns another Ranger that is a multiple of blockSize in length. The return value padding is a convenience to report how much padding was added.

func PadReader

func PadReader(data io.ReadCloser, blockSize int) io.ReadCloser

PadReader is like Pad but works on a basic Reader instead of a Ranger.

func Transform

func Transform(rr ranger.Ranger, t Transformer) (ranger.Ranger, error)

Transform will apply a Transformer to a Ranger.

func TransformReader

func TransformReader(r io.ReadCloser, t Transformer,
	startingBlockNum int64) io.ReadCloser

TransformReader applies a Transformer to a Reader. startingBlockNum should probably be 0 unless you know you're already starting at a block offset.

func TransformReaderSize

func TransformReaderSize(r io.ReadCloser, t Transformer,
	startingBlockNum int64, expectedSize int64) io.ReadCloser

TransformReaderSize creates a TransformReader with expected size, i.e. the number of bytes that is expected to be read from this reader. If less than the expected bytes are read, the reader will return io.ErrUnexpectedEOF instead of io.EOF.

func TransformWriterPadded

func TransformWriterPadded(w io.Writer, t Transformer) io.WriteCloser

TransformWriterPadded applies a Transformer to a Writer. It also applies padding to the output bytes.

func Unpad

func Unpad(data ranger.Ranger, padding int) (ranger.Ranger, error)

Unpad takes a previously padded Ranger data source and returns an unpadded ranger, given the amount of padding. This is preferable to UnpadSlow if you can swing it.

func UnpadSlow

func UnpadSlow(ctx context.Context, data ranger.Ranger) (_ ranger.Ranger, err error)

UnpadSlow is like Unpad, but does not require the amount of padding. UnpadSlow will have to do extra work to make up for this missing information.

Types

type AESGCMNonce

type AESGCMNonce [AESGCMNonceSize]byte

AESGCMNonce represents the nonce used by the AES-GCM protocol.

func ToAESGCMNonce

func ToAESGCMNonce(nonce *storj.Nonce) *AESGCMNonce

ToAESGCMNonce returns the nonce as a AES-GCM nonce.

type Base

type Base struct {
	Unencrypted paths.Unencrypted
	Encrypted   paths.Encrypted
	Key         storj.Key
	PathCipher  storj.CipherSuite
	Default     bool
}

Base represents a key with which to derive further keys at some encrypted/unencrypted path.

type NoopTransformer

type NoopTransformer struct{}

NoopTransformer is a dummy Transformer that passes data through without modifying it.

func (*NoopTransformer) InBlockSize

func (t *NoopTransformer) InBlockSize() int

InBlockSize is 1.

func (*NoopTransformer) OutBlockSize

func (t *NoopTransformer) OutBlockSize() int

OutBlockSize is 1.

func (*NoopTransformer) Transform

func (t *NoopTransformer) Transform(out, in []byte, blockNum int64) ([]byte, error)

Transform returns the input without modification.

type PrefixInfo

type PrefixInfo struct {
	Bucket string
	Cipher storj.CipherSuite

	PathUnenc paths.Unencrypted
	PathEnc   paths.Encrypted
	PathKey   storj.Key

	ParentUnenc paths.Unencrypted
	ParentEnc   paths.Encrypted
	ParentKey   storj.Key
}

PrefixInfo is a helper type that contains all of the encrypted and unencrypted paths related to some path and its parent. It includes the cipher that was used to encrypt and decrypt the paths and what bucket it is in.

func GetPrefixInfo

func GetPrefixInfo(bucket string, path paths.Unencrypted, store *Store) (pi *PrefixInfo, err error)

GetPrefixInfo returns the PrefixInfo for some unencrypted path inside of a bucket.

type Store

type Store struct {

	// EncryptionBypass makes it so we can interoperate with
	// the network without having encryption keys. paths will be encrypted but
	// base64-encoded, and certain metadata will be unable to be retrieved.
	// If it is true, all PathCiphers returned in the base for any Lookup call
	// will return storj.EncNullBase64URL. Iterate is unaffected.
	EncryptionBypass bool
	// contains filtered or unexported fields
}

The Store allows one to find the matching most encrypted key and path for some unencrypted path. It also reports a mapping of encrypted to unencrypted paths at the searched for unencrypted path.

For example, if the Store contains the mappings

b1, u1/u2/u3    => <e1/e2/e3, k3>
b1, u1/u2/u3/u4 => <e1/e2/e3/e4, k4>
b1, u1/u5       => <e1/e5, k5>
b1, u6          => <e6, k6>
b1, u6/u7/u8    => <e6/e7/e8, k8>
b2, u1          => <e1', k1'>

then the following lookups have outputs:

b1, u1          => <{e2:u2, e5:u5}, [], nil>
b1, u1/u2/u3    => <{e4:u4}, [], <u1/u2/u3, e1/e2/e3, k3>>
b1, u1/u2/u3/u6 => <{}, [u6], <u1/u2/u3, e1/e2/e3, k3>>
b1, u1/u2/u3/u4 => <{}, [], <u1/u2/u3/u4, e1/e2/e3/e4, k4>>
b1, u6/u7       => <{e8:u8}, [u7], <u6, e6, k6>>
b2, u1          => <{}, [u1], <u1, e1', k1'>>
Example
s := NewStore()
ep := paths.NewEncrypted
up := paths.NewUnencrypted

// Add a fairly complicated tree to the store.
abortIfError(s.AddWithCipher("b1", up("u1/u2/u3"), ep("e1/e2/e3"), toKey("k3"), storj.EncAESGCM))
abortIfError(s.AddWithCipher("b1", up("u1/u2/u3/u4"), ep("e1/e2/e3/e4"), toKey("k4"), storj.EncAESGCM))
abortIfError(s.AddWithCipher("b1", up("u1/u5"), ep("e1/e5"), toKey("k5"), storj.EncAESGCM))
abortIfError(s.AddWithCipher("b1", up("u6"), ep("e6"), toKey("k6"), storj.EncAESGCM))
abortIfError(s.AddWithCipher("b1", up("u6/u7/u8"), ep("e6/e7/e8"), toKey("k8"), storj.EncAESGCM))
abortIfError(s.AddWithCipher("b2", up("u1"), ep("e1'"), toKey("k1"), storj.EncAESGCM))
abortIfError(s.AddWithCipher("b3", paths.Unencrypted{}, paths.Encrypted{}, toKey("m1"), storj.EncAESGCM))

// Look up some complicated queries by the unencrypted path.
printLookup(s.LookupUnencrypted("b1", up("u1")))
printLookup(s.LookupUnencrypted("b1", up("u1/u2/u3")))
printLookup(s.LookupUnencrypted("b1", up("u1/u2/u3/u6")))
printLookup(s.LookupUnencrypted("b1", up("u1/u2/u3/u4")))
printLookup(s.LookupUnencrypted("b1", up("u6/u7")))
printLookup(s.LookupUnencrypted("b2", up("u1")))
printLookup(s.LookupUnencrypted("b3", paths.Unencrypted{}))
printLookup(s.LookupUnencrypted("b3", up("z1")))

fmt.Println()

// Look up some complicated queries by the encrypted path.
printLookup(s.LookupEncrypted("b1", ep("e1")))
printLookup(s.LookupEncrypted("b1", ep("e1/e2/e3")))
printLookup(s.LookupEncrypted("b1", ep("e1/e2/e3/e6")))
printLookup(s.LookupEncrypted("b1", ep("e1/e2/e3/e4")))
printLookup(s.LookupEncrypted("b1", ep("e6/e7")))
printLookup(s.LookupEncrypted("b2", ep("e1'")))
printLookup(s.LookupEncrypted("b3", paths.Encrypted{}))
printLookup(s.LookupEncrypted("b3", ep("z1")))
Output:


<map["e2":"u2" "e5":"u5"], [], nil>
<map["e4":"u4"], [], <"u1/u2/u3", "e1/e2/e3", "k3", false>>
<map[], ["u6"], <"u1/u2/u3", "e1/e2/e3", "k3", false>>
<map[], [], <"u1/u2/u3/u4", "e1/e2/e3/e4", "k4", false>>
<map["e8":"u8"], ["u7"], <"u6", "e6", "k6", false>>
<map[], [], <"u1", "e1'", "k1", false>>
<map[], [], <"", "", "m1", false>>
<map[], ["z1"], <"", "", "m1", false>>

<map["u2":"e2" "u5":"e5"], [], nil>
<map["u4":"e4"], [], <"u1/u2/u3", "e1/e2/e3", "k3", false>>
<map[], ["e6"], <"u1/u2/u3", "e1/e2/e3", "k3", false>>
<map[], [], <"u1/u2/u3/u4", "e1/e2/e3/e4", "k4", false>>
<map["u8":"e8"], ["e7"], <"u6", "e6", "k6", false>>
<map[], [], <"u1", "e1'", "k1", false>>
<map[], [], <"", "", "m1", false>>
<map[], ["z1"], <"", "", "m1", false>>

func NewStore

func NewStore() *Store

NewStore constructs a Store.

func (*Store) Add

func (s *Store) Add(bucket string, unenc paths.Unencrypted, enc paths.Encrypted, key storj.Key) error

Add creates a mapping from the unencrypted path to the encrypted path and key. It uses the current default cipher.

func (*Store) AddWithCipher

func (s *Store) AddWithCipher(bucket string, unenc paths.Unencrypted, enc paths.Encrypted, key storj.Key, pathCipher storj.CipherSuite) error

AddWithCipher creates a mapping from the unencrypted path to the encrypted path and key with the given cipher.

func (*Store) Clone

func (s *Store) Clone() *Store

Clone returns a deep copy of Store.

func (*Store) GetDefaultKey

func (s *Store) GetDefaultKey() *storj.Key

GetDefaultKey returns the default key, or nil if none has been set.

func (*Store) GetDefaultPathCipher

func (s *Store) GetDefaultPathCipher() storj.CipherSuite

GetDefaultPathCipher returns the default path cipher, or EncUnspecified if none has been set.

func (*Store) Iterate

func (s *Store) Iterate(fn func(string, paths.Unencrypted, paths.Encrypted, storj.Key) error) error

Iterate executes the callback with every value that has been Added to the Store. NOTE: This call is lossy! Please upgrade any code paths to use IterateWithCipher!

func (*Store) IterateWithCipher

func (s *Store) IterateWithCipher(fn func(string, paths.Unencrypted, paths.Encrypted, storj.Key, storj.CipherSuite) error) error

IterateWithCipher executes the callback with every value that has been Added to the Store.

func (*Store) LookupEncrypted

func (s *Store) LookupEncrypted(bucket string, path paths.Encrypted) (
	revealed map[string]string, remaining paths.Iterator, base *Base)

LookupEncrypted finds the matching most encrypted path added to the Store, reports how much of the path matched, any known encrypted paths at the requested path, and if a key an encrypted path exists for some prefix of the encrypted path.

func (*Store) LookupUnencrypted

func (s *Store) LookupUnencrypted(bucket string, path paths.Unencrypted) (
	revealed map[string]string, remaining paths.Iterator, base *Base)

LookupUnencrypted finds the matching most unencrypted path added to the Store, reports how much of the path matched, any known unencrypted paths at the requested path, and if a key and encrypted path exists for some prefix of the unencrypted path.

func (*Store) SetDefaultKey

func (s *Store) SetDefaultKey(defaultKey *storj.Key)

SetDefaultKey adds a default key to be returned for any lookup that does not match a bucket.

Example
s := NewStore()
dk := toKey("dk")
s.SetDefaultKey(&dk)
ep := paths.NewEncrypted
up := paths.NewUnencrypted

abortIfError(s.AddWithCipher("b1", up("u1/u2/u3"), ep("e1/e2/e3"), toKey("k3"), storj.EncAESGCM))

printLookup(s.LookupUnencrypted("b1", up("u1")))
printLookup(s.LookupUnencrypted("b1", up("u1/u2")))
printLookup(s.LookupUnencrypted("b1", up("u1/u2/u3")))
printLookup(s.LookupUnencrypted("b1", up("u1/u2/u3/u4")))

fmt.Println()

printLookup(s.LookupEncrypted("b1", ep("e1")))
printLookup(s.LookupEncrypted("b1", ep("e1/e2")))
printLookup(s.LookupEncrypted("b1", ep("e1/e2/e3")))
printLookup(s.LookupEncrypted("b1", ep("e1/e2/e3/e4")))
Output:


<map[], ["u1"], <"", "", "dk", true>>
<map[], ["u1" "u2"], <"", "", "dk", true>>
<map[], [], <"u1/u2/u3", "e1/e2/e3", "k3", false>>
<map[], ["u4"], <"u1/u2/u3", "e1/e2/e3", "k3", false>>

<map[], ["e1"], <"", "", "dk", true>>
<map[], ["e1" "e2"], <"", "", "dk", true>>
<map[], [], <"u1/u2/u3", "e1/e2/e3", "k3", false>>
<map[], ["e4"], <"u1/u2/u3", "e1/e2/e3", "k3", false>>

func (*Store) SetDefaultPathCipher

func (s *Store) SetDefaultPathCipher(defaultPathCipher storj.CipherSuite)

SetDefaultPathCipher adds a default path cipher to be returned for any lookup that does not match a bucket.

type Transformer

type Transformer interface {
	InBlockSize() int  // The block size prior to transformation
	OutBlockSize() int // The block size after transformation
	Transform(out, in []byte, blockNum int64) ([]byte, error)
}

A Transformer is a data transformation that may change the size of the blocks of data it operates on in a deterministic fashion.

func NewAESGCMDecrypter

func NewAESGCMDecrypter(key *storj.Key, startingNonce *AESGCMNonce, encryptedBlockSize int) (Transformer, error)

NewAESGCMDecrypter returns a Transformer that decrypts the data passing through with key. See the comments for NewAESGCMEncrypter about startingNonce.

func NewAESGCMEncrypter

func NewAESGCMEncrypter(key *storj.Key, startingNonce *AESGCMNonce, encryptedBlockSize int) (Transformer, error)

NewAESGCMEncrypter returns a Transformer that encrypts the data passing through with key.

startingNonce is treated as a big-endian encoded unsigned integer, and as blocks pass through, their block number and the starting nonce is added together to come up with that block's nonce. Encrypting different data with the same key and the same nonce is a huge security issue. It's safe to always encode new data with a random key and random startingNonce. The monotonically-increasing nonce (that rolls over) is to protect against data reordering.

When in doubt, generate a new key from crypto/rand and a startingNonce from crypto/rand as often as possible.

func NewDecrypter

func NewDecrypter(cipher storj.CipherSuite, key *storj.Key, startingNonce *storj.Nonce, encryptedBlockSize int) (Transformer, error)

NewDecrypter creates a Transformer using the given cipher, key and nonce to decrypt data passing through it.

func NewEncrypter

func NewEncrypter(cipher storj.CipherSuite, key *storj.Key, startingNonce *storj.Nonce, encryptedBlockSize int) (Transformer, error)

NewEncrypter creates a Transformer using the given cipher, key and nonce to encrypt data passing through it.

func NewSecretboxDecrypter

func NewSecretboxDecrypter(key *storj.Key, startingNonce *storj.Nonce, encryptedBlockSize int) (Transformer, error)

NewSecretboxDecrypter returns a Transformer that decrypts the data passing through with key. See the comments for NewSecretboxEncrypter about startingNonce.

func NewSecretboxEncrypter

func NewSecretboxEncrypter(key *storj.Key, startingNonce *storj.Nonce, encryptedBlockSize int) (Transformer, error)

NewSecretboxEncrypter returns a Transformer that encrypts the data passing through with key.

startingNonce is treated as a big-endian encoded unsigned integer, and as blocks pass through, their block number and the starting nonce is added together to come up with that block's nonce. Encrypting different data with the same key and the same nonce is a huge security issue. It's safe to always encode new data with a random key and random startingNonce. The monotonically-increasing nonce (that rolls over) is to protect against data reordering.

When in doubt, generate a new key from crypto/rand and a startingNonce from crypto/rand as often as possible.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL