gitlab.com/SiaPrime/SiaPrime@v1.4.1/crypto/twofish.go (about) 1 package crypto 2 3 import ( 4 "crypto/cipher" 5 "fmt" 6 7 "gitlab.com/NebulousLabs/errors" 8 "gitlab.com/NebulousLabs/fastrand" 9 "golang.org/x/crypto/twofish" 10 ) 11 12 const ( 13 // twofishOverhead is the number of bytes added by EncryptBytes. 14 twofishOverhead = 28 15 ) 16 17 var ( 18 // ErrInsufficientLen is an error when supplied ciphertext is not 19 // long enough to contain a nonce. 20 ErrInsufficientLen = errors.New("supplied ciphertext is not long enough to contain a nonce") 21 ) 22 23 type ( 24 // TwofishKey is a key used for encrypting and decrypting data. 25 TwofishKey [EntropySize]byte 26 ) 27 28 // generateTwofishKey produces a TwofishKey that can be used for encrypting and 29 // decrypting data using Twofish-GCM. 30 func generateTwofishKey() (key TwofishKey) { 31 fastrand.Read(key[:]) 32 return 33 } 34 35 // newCipher creates a new Twofish cipher from the key. 36 func (key TwofishKey) newCipher() cipher.Block { 37 cipher, err := twofish.NewCipher(key[:]) 38 if err != nil { 39 panic("NewCipher only returns an error if len(key) != 16, 24, or 32.") 40 } 41 return cipher 42 } 43 44 // newTwofishKey creates a new TwofishKey from a given entropy. 45 func newTwofishKey(entropy []byte) (key TwofishKey, err error) { 46 // check key length 47 if len(entropy) != len(key) { 48 err = fmt.Errorf("twofish key should have size %v but was %v", 49 EntropySize, len(entropy)) 50 return 51 } 52 // create key 53 copy(key[:], entropy) 54 return 55 } 56 57 // DecryptBytes decrypts a ciphertext created by EncryptPiece. The nonce is 58 // expected to be the first 12 bytes of the ciphertext. 59 func (key TwofishKey) DecryptBytes(ct Ciphertext) ([]byte, error) { 60 // Create the cipher. 61 aead, err := cipher.NewGCM(key.newCipher()) 62 if err != nil { 63 return nil, errors.AddContext(err, "NewGCM should only return an error if twofishCipher.BlockSize != 16") 64 } 65 return DecryptWithNonce(ct, aead) 66 } 67 68 // DecryptBytesInPlace decrypts the ciphertext created by EncryptBytes. The 69 // nonce is expected to be the first 12 bytes of the ciphertext. 70 // DecryptBytesInPlace reuses the memory of ct to be able to operate in-place. 71 // This means that ct can't be reused after calling DecryptBytesInPlace. 72 func (key TwofishKey) DecryptBytesInPlace(ct Ciphertext, blockIndex uint64) ([]byte, error) { 73 if blockIndex != 0 { 74 return nil, errors.New("twofish doesn't support a blockIndex != 0") 75 } 76 // Create the cipher. 77 aead, err := cipher.NewGCM(key.newCipher()) 78 if err != nil { 79 return nil, errors.AddContext(err, "NewGCM should only return an error if twofishCipher.BlockSize != 16") 80 } 81 82 // Check for a nonce. 83 if len(ct) < aead.NonceSize() { 84 return nil, ErrInsufficientLen 85 } 86 87 // Decrypt the data. 88 nonce := ct[:aead.NonceSize()] 89 ciphertext := ct[aead.NonceSize():] 90 return aead.Open(ciphertext[:0], nonce, ciphertext, nil) 91 } 92 93 // Derive derives a child key for a given combination of chunk and piece index. 94 func (key TwofishKey) Derive(chunkIndex, pieceIndex uint64) CipherKey { 95 entropy := HashAll(key, chunkIndex, pieceIndex) 96 ck, err := NewSiaKey(TypeTwofish, entropy[:]) 97 if err != nil { 98 panic("this should not be possible when deriving from a valid key") 99 } 100 return ck 101 } 102 103 // EncryptBytes encrypts arbitrary data using the TwofishKey, prepending a 12 104 // byte nonce to the ciphertext in the process. GCM and prepends the nonce (12 105 // bytes) to the ciphertext. 106 func (key TwofishKey) EncryptBytes(piece []byte) Ciphertext { 107 // Create the cipher. 108 aead, err := cipher.NewGCM(key.newCipher()) 109 if err != nil { 110 panic("NewGCM only returns an error if twofishCipher.BlockSize != 16") 111 } 112 return EncryptWithNonce(piece, aead) 113 } 114 115 // Key returns the twofish key. 116 func (key TwofishKey) Key() []byte { 117 return key[:] 118 } 119 120 // Type returns the type of the twofish key. 121 func (TwofishKey) Type() CipherType { 122 return TypeTwofish 123 }