mirror of https://github.com/minio/minio.git
94 lines
3.1 KiB
Go
94 lines
3.1 KiB
Go
// Minio Cloud Storage, (C) 2015, 2016, 2017, 2018 Minio, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package crypto
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/hmac"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
"path/filepath"
|
|
|
|
"github.com/minio/minio/cmd/logger"
|
|
sha256 "github.com/minio/sha256-simd"
|
|
"github.com/minio/sio"
|
|
)
|
|
|
|
// ObjectKey is a 256 bit secret key used to encrypt the object.
|
|
// It must never be stored in plaintext.
|
|
type ObjectKey [32]byte
|
|
|
|
// GenerateKey generates a unique ObjectKey from a 256 bit external key
|
|
// and a source of randomness. If random is nil the default PRNG of system
|
|
// (crypto/rand) is used.
|
|
func GenerateKey(extKey [32]byte, random io.Reader) (key ObjectKey) {
|
|
if random == nil {
|
|
random = rand.Reader
|
|
}
|
|
var nonce [32]byte
|
|
if _, err := io.ReadFull(random, nonce[:]); err != nil {
|
|
logger.CriticalIf(context.Background(), errors.New("Unable to read enough randomness from the system"))
|
|
}
|
|
sha := sha256.New()
|
|
sha.Write(extKey[:])
|
|
sha.Write(nonce[:])
|
|
sha.Sum(key[:0])
|
|
return
|
|
}
|
|
|
|
// Seal encrypts the ObjectKey using the 256 bit external key and IV. The sealed
|
|
// key is also cryptographically bound to the object's path (bucket/object).
|
|
func (key ObjectKey) Seal(extKey, iv [32]byte, bucket, object string) []byte {
|
|
var sealedKey bytes.Buffer
|
|
mac := hmac.New(sha256.New, extKey[:])
|
|
mac.Write(iv[:])
|
|
mac.Write([]byte(filepath.Join(bucket, object)))
|
|
|
|
if n, err := sio.Encrypt(&sealedKey, bytes.NewReader(key[:]), sio.Config{Key: mac.Sum(nil)}); n != 64 || err != nil {
|
|
logger.CriticalIf(context.Background(), errors.New("Unable to generate sealed key"))
|
|
}
|
|
return sealedKey.Bytes()
|
|
}
|
|
|
|
// Unseal decrypts a sealed key using the 256 bit external key and IV. Since the sealed key
|
|
// is cryptographically bound to the object's path the same bucket/object as during sealing
|
|
// must be provided. On success the ObjectKey contains the decrypted sealed key.
|
|
func (key *ObjectKey) Unseal(sealedKey []byte, extKey, iv [32]byte, bucket, object string) error {
|
|
var unsealedKey bytes.Buffer
|
|
mac := hmac.New(sha256.New, extKey[:])
|
|
mac.Write(iv[:])
|
|
mac.Write([]byte(filepath.Join(bucket, object)))
|
|
|
|
if n, err := sio.Decrypt(&unsealedKey, bytes.NewReader(sealedKey), sio.Config{Key: mac.Sum(nil)}); n != 32 || err != nil {
|
|
return err // TODO(aead): upgrade sio to use sio.Error
|
|
}
|
|
copy(key[:], unsealedKey.Bytes())
|
|
return nil
|
|
}
|
|
|
|
// DerivePartKey derives an unique 256 bit key from an ObjectKey and the part index.
|
|
func (key ObjectKey) DerivePartKey(id uint32) (partKey [32]byte) {
|
|
var bin [4]byte
|
|
binary.LittleEndian.PutUint32(bin[:], id)
|
|
|
|
mac := hmac.New(sha256.New, key[:])
|
|
mac.Write(bin[:])
|
|
mac.Sum(partKey[:0])
|
|
return
|
|
}
|