1717package auth
1818
1919import (
20+ "bytes"
2021 "crypto/aes"
2122 "crypto/cipher"
22- "crypto/rand "
23+ "crypto/hmac "
2324 "crypto/sha1"
25+ "crypto/sha256"
2426 "encoding/base64"
2527 "errors"
2628 "fmt"
2729 "io"
30+ "io/ioutil"
2831 "log"
2932 "net/http"
3033 "strings"
@@ -33,13 +36,17 @@ import (
3336 "github.com/minio/console/models"
3437 "github.com/minio/console/pkg/auth/token"
3538 "github.com/minio/minio-go/v7/pkg/credentials"
39+ "github.com/secure-io/sio-go/sioutil"
40+ "golang.org/x/crypto/chacha20"
41+ "golang.org/x/crypto/chacha20poly1305"
3642 "golang.org/x/crypto/pbkdf2"
3743)
3844
3945var (
4046 errNoAuthToken = errors .New ("session token missing" )
4147 errReadingToken = errors .New ("session token internal data is malformed" )
4248 errClaimsFormat = errors .New ("encrypted session token claims not in the right format" )
49+ errorGeneric = errors .New ("an error has occurred" )
4350)
4451
4552// derivedKey is the key used to encrypt the session token claims, its derived using pbkdf on CONSOLE_PBKDF_PASSPHRASE with CONSOLE_PBKDF_SALT
@@ -102,9 +109,10 @@ func NewEncryptedTokenForClient(credentials *credentials.Value, actions []string
102109// returns a base64 encoded ciphertext
103110func encryptClaims (accessKeyID , secretAccessKey , sessionToken string , actions []string ) (string , error ) {
104111 payload := []byte (fmt .Sprintf ("%s#%s#%s#%s" , accessKeyID , secretAccessKey , sessionToken , strings .Join (actions , "," )))
105- ciphertext , err := encrypt (payload )
112+ ciphertext , err := encrypt (payload , [] byte {} )
106113 if err != nil {
107- return "" , err
114+ log .Println (err )
115+ return "" , errorGeneric
108116 }
109117 return base64 .StdEncoding .EncodeToString (ciphertext ), nil
110118}
@@ -116,7 +124,7 @@ func decryptClaims(ciphertext string) (*DecryptedClaims, error) {
116124 log .Println (err )
117125 return nil , errClaimsFormat
118126 }
119- plaintext , err := decrypt (decoded )
127+ plaintext , err := decrypt (decoded , [] byte {} )
120128 if err != nil {
121129 log .Println (err )
122130 return nil , errClaimsFormat
@@ -136,37 +144,137 @@ func decryptClaims(ciphertext string) (*DecryptedClaims, error) {
136144 }, nil
137145}
138146
139- // Encrypt a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
140- func encrypt (plaintext []byte ) ([]byte , error ) {
141- block , _ := aes .NewCipher (derivedKey )
142- gcm , err := cipher .NewGCM (block )
147+ const (
148+ aesGcm = 0x00
149+ c20p1305 = 0x01
150+ )
151+
152+ // Encrypt a blob of data using AEAD scheme, AES-GCM if the executing CPU
153+ // provides AES hardware support, otherwise will use ChaCha20-Poly1305
154+ // with a pbkdf2 derived key, this function should be used to encrypt a session
155+ // or data key provided as plaintext.
156+ //
157+ // The returned ciphertext data consists of:
158+ // iv | AEAD ID | nonce | encrypted data
159+ // 32 1 12 ~ len(data)
160+ func encrypt (plaintext , associatedData []byte ) ([]byte , error ) {
161+ iv , err := sioutil .Random (32 ) // 32 bit IV
143162 if err != nil {
144163 return nil , err
145164 }
146- nonce := make ([]byte , gcm .NonceSize ())
147- if _ , err = io .ReadFull (rand .Reader , nonce ); err != nil {
165+ var algorithm byte
166+ if sioutil .NativeAES () {
167+ algorithm = aesGcm
168+ } else {
169+ algorithm = c20p1305
170+ }
171+ var aead cipher.AEAD
172+ switch algorithm {
173+ case aesGcm :
174+ mac := hmac .New (sha256 .New , derivedKey )
175+ mac .Write (iv )
176+ sealingKey := mac .Sum (nil )
177+
178+ var block cipher.Block
179+ block , err = aes .NewCipher (sealingKey )
180+ if err != nil {
181+ return nil , err
182+ }
183+ aead , err = cipher .NewGCM (block )
184+ if err != nil {
185+ return nil , err
186+ }
187+ case c20p1305 :
188+ var sealingKey []byte
189+ sealingKey , err = chacha20 .HChaCha20 (derivedKey , iv )
190+ if err != nil {
191+ return nil , err
192+ }
193+ aead , err = chacha20poly1305 .New (sealingKey )
194+ if err != nil {
195+ return nil , err
196+ }
197+ }
198+ nonce , err := sioutil .Random (aead .NonceSize ())
199+ if err != nil {
148200 return nil , err
149201 }
150- cipherText := gcm .Seal (nonce , nonce , plaintext , nil )
151- return cipherText , nil
202+
203+ sealedBytes := aead .Seal (nil , nonce , plaintext , associatedData )
204+
205+ // ciphertext = iv | AEAD ID | nonce | sealed bytes
206+
207+ var buf bytes.Buffer
208+ buf .Write (iv )
209+ buf .WriteByte (algorithm )
210+ buf .Write (nonce )
211+ buf .Write (sealedBytes )
212+
213+ return buf .Bytes (), nil
152214}
153215
154- // Decrypts a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
155- func decrypt (data []byte ) ([]byte , error ) {
156- block , err := aes .NewCipher (derivedKey )
157- if err != nil {
216+ // Decrypts a blob of data using AEAD scheme AES-GCM if the executing CPU
217+ // provides AES hardware support, otherwise will use ChaCha20-Poly1305with
218+ // and a pbkdf2 derived key
219+ func decrypt (ciphertext []byte , associatedData []byte ) ([]byte , error ) {
220+ var (
221+ iv [32 ]byte
222+ algorithm [1 ]byte
223+ nonce [12 ]byte // This depends on the AEAD but both used ciphers have the same nonce length.
224+ )
225+
226+ r := bytes .NewReader (ciphertext )
227+ if _ , err := io .ReadFull (r , iv [:]); err != nil {
228+ return nil , err
229+ }
230+ if _ , err := io .ReadFull (r , algorithm [:]); err != nil {
231+ return nil , err
232+ }
233+ if _ , err := io .ReadFull (r , nonce [:]); err != nil {
158234 return nil , err
159235 }
160- gcm , err := cipher .NewGCM (block )
236+
237+ var aead cipher.AEAD
238+ switch algorithm [0 ] {
239+ case aesGcm :
240+ mac := hmac .New (sha256 .New , derivedKey )
241+ mac .Write (iv [:])
242+ sealingKey := mac .Sum (nil )
243+ block , err := aes .NewCipher (sealingKey [:])
244+ if err != nil {
245+ return nil , err
246+ }
247+ aead , err = cipher .NewGCM (block )
248+ if err != nil {
249+ return nil , err
250+ }
251+ case c20p1305 :
252+ sealingKey , err := chacha20 .HChaCha20 (derivedKey , iv [:])
253+ if err != nil {
254+ return nil , err
255+ }
256+ aead , err = chacha20poly1305 .New (sealingKey )
257+ if err != nil {
258+ return nil , err
259+ }
260+ default :
261+ return nil , fmt .Errorf ("invalid algorithm: %v" , algorithm )
262+ }
263+
264+ if len (nonce ) != aead .NonceSize () {
265+ return nil , fmt .Errorf ("invalid nonce size %d, expected %d" , len (nonce ), aead .NonceSize ())
266+ }
267+
268+ sealedBytes , err := ioutil .ReadAll (r )
161269 if err != nil {
162270 return nil , err
163271 }
164- nonceSize := gcm .NonceSize ()
165- nonce , cipherText := data [:nonceSize ], data [nonceSize :]
166- plaintext , err := gcm .Open (nil , nonce , cipherText , nil )
272+
273+ plaintext , err := aead .Open (nil , nonce [:], sealedBytes , associatedData )
167274 if err != nil {
168275 return nil , err
169276 }
277+
170278 return plaintext , nil
171279}
172280
0 commit comments