github.com/ZuluSpl0it/Sia@v1.3.7/crypto/encrypt.go (about) 1 package crypto 2 3 // encrypt.go contains functions for encrypting and decrypting data byte slices 4 // and readers. 5 6 import ( 7 "crypto/cipher" 8 "encoding/json" 9 "errors" 10 "io" 11 12 "github.com/NebulousLabs/fastrand" 13 14 "golang.org/x/crypto/twofish" 15 ) 16 17 const ( 18 // TwofishOverhead is the number of bytes added by EncryptBytes 19 TwofishOverhead = 28 20 ) 21 22 var ( 23 // ErrInsufficientLen is an error when supplied ciphertext is not 24 // long enough to contain a nonce. 25 ErrInsufficientLen = errors.New("supplied ciphertext is not long enough to contain a nonce") 26 ) 27 28 type ( 29 // Ciphertext is an encrypted []byte. 30 Ciphertext []byte 31 // TwofishKey is a key used for encrypting and decrypting data. 32 TwofishKey [EntropySize]byte 33 ) 34 35 // GenerateTwofishKey produces a key that can be used for encrypting and 36 // decrypting files. 37 func GenerateTwofishKey() (key TwofishKey) { 38 fastrand.Read(key[:]) 39 return 40 } 41 42 // NewCipher creates a new Twofish cipher from the key. 43 func (key TwofishKey) NewCipher() cipher.Block { 44 // NOTE: NewCipher only returns an error if len(key) != 16, 24, or 32. 45 cipher, _ := twofish.NewCipher(key[:]) 46 return cipher 47 } 48 49 // EncryptBytes encrypts a []byte using the key. EncryptBytes uses GCM and 50 // prepends the nonce (12 bytes) to the ciphertext. 51 func (key TwofishKey) EncryptBytes(plaintext []byte) Ciphertext { 52 // Create the cipher. 53 // NOTE: NewGCM only returns an error if twofishCipher.BlockSize != 16. 54 aead, _ := cipher.NewGCM(key.NewCipher()) 55 56 // Create the nonce. 57 nonce := fastrand.Bytes(aead.NonceSize()) 58 59 // Encrypt the data. No authenticated data is provided, as EncryptBytes is 60 // meant for file encryption. 61 return aead.Seal(nonce, nonce, plaintext, nil) 62 } 63 64 // DecryptBytes decrypts the ciphertext created by EncryptBytes. The nonce is 65 // expected to be the first 12 bytes of the ciphertext. 66 func (key TwofishKey) DecryptBytes(ct Ciphertext) ([]byte, error) { 67 // Create the cipher. 68 // NOTE: NewGCM only returns an error if twofishCipher.BlockSize != 16. 69 aead, _ := cipher.NewGCM(key.NewCipher()) 70 71 // Check for a nonce. 72 if len(ct) < aead.NonceSize() { 73 return nil, ErrInsufficientLen 74 } 75 76 // Decrypt the data. 77 nonce := ct[:aead.NonceSize()] 78 ciphertext := ct[aead.NonceSize():] 79 return aead.Open(nil, nonce, ciphertext, nil) 80 } 81 82 // DecryptBytesInPlace decrypts the ciphertext created by EncryptBytes. The 83 // nonce is expected to be the first 12 bytes of the ciphertext. 84 // DecryptBytesInPlace reuses the memory of ct to be able to operate in-place. 85 // This means that ct can't be reused after calling DecryptBytesInPlace. 86 func (key TwofishKey) DecryptBytesInPlace(ct Ciphertext) ([]byte, error) { 87 // Create the cipher. 88 // NOTE: NewGCM only returns an error if twofishCipher.BlockSize != 16. 89 aead, _ := cipher.NewGCM(key.NewCipher()) 90 91 // Check for a nonce. 92 if len(ct) < aead.NonceSize() { 93 return nil, ErrInsufficientLen 94 } 95 96 // Decrypt the data. 97 nonce := ct[:aead.NonceSize()] 98 ciphertext := ct[aead.NonceSize():] 99 return aead.Open(ciphertext[:0], nonce, ciphertext, nil) 100 } 101 102 // NewWriter returns a writer that encrypts or decrypts its input stream. 103 func (key TwofishKey) NewWriter(w io.Writer) io.Writer { 104 // OK to use a zero IV if the key is unique for each ciphertext. 105 iv := make([]byte, twofish.BlockSize) 106 stream := cipher.NewOFB(key.NewCipher(), iv) 107 108 return &cipher.StreamWriter{S: stream, W: w} 109 } 110 111 // NewReader returns a reader that encrypts or decrypts its input stream. 112 func (key TwofishKey) NewReader(r io.Reader) io.Reader { 113 // OK to use a zero IV if the key is unique for each ciphertext. 114 iv := make([]byte, twofish.BlockSize) 115 stream := cipher.NewOFB(key.NewCipher(), iv) 116 117 return &cipher.StreamReader{S: stream, R: r} 118 } 119 120 // MarshalJSON returns the JSON encoding of a CipherText 121 func (c Ciphertext) MarshalJSON() ([]byte, error) { 122 return json.Marshal([]byte(c)) 123 } 124 125 // UnmarshalJSON parses the JSON-encoded b and returns an instance of 126 // CipherText. 127 func (c *Ciphertext) UnmarshalJSON(b []byte) error { 128 var umarB []byte 129 err := json.Unmarshal(b, &umarB) 130 if err != nil { 131 return err 132 } 133 *c = Ciphertext(umarB) 134 return nil 135 }