123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- package osscrypto
- import (
- "fmt"
- "io"
- "os"
- "strconv"
- "github.com/aliyun/aliyun-oss-go-sdk/oss"
- )
- // PartCryptoContext save encryption or decryption information
- type PartCryptoContext struct {
- ContentCipher ContentCipher
- DataSize int64
- PartSize int64
- }
- // Valid judge PartCryptoContext is valid or not
- func (pcc PartCryptoContext) Valid() bool {
- if pcc.ContentCipher == nil || pcc.DataSize == 0 || pcc.PartSize == 0 {
- return false
- }
- return true
- }
- // InitiateMultipartUpload initializes multipart upload for client encryption
- // cryptoContext.PartSize and cryptoContext.DataSize are input parameter
- // cryptoContext.PartSize must aligned to the secret iv length
- // cryptoContext.ContentCipher is output parameter
- // cryptoContext will be used in next API
- func (bucket CryptoBucket) InitiateMultipartUpload(objectKey string, cryptoContext *PartCryptoContext, options ...oss.Option) (oss.InitiateMultipartUploadResult, error) {
- options = bucket.AddEncryptionUaSuffix(options)
- var imur oss.InitiateMultipartUploadResult
- if cryptoContext == nil {
- return imur, fmt.Errorf("error,cryptoContext is nil")
- }
- if cryptoContext.PartSize <= 0 {
- return imur, fmt.Errorf("invalid PartCryptoContext's PartSize %d", cryptoContext.PartSize)
- }
- cc, err := bucket.ContentCipherBuilder.ContentCipher()
- if err != nil {
- return imur, err
- }
- if cryptoContext.PartSize%int64(cc.GetAlignLen()) != 0 {
- return imur, fmt.Errorf("PartCryptoContext's PartSize must be aligned to %d", cc.GetAlignLen())
- }
- opts := addCryptoHeaders(options, cc.GetCipherData())
- if cryptoContext.DataSize > 0 {
- opts = append(opts, oss.Meta(OssClientSideEncryptionDataSize, strconv.FormatInt(cryptoContext.DataSize, 10)))
- }
- opts = append(opts, oss.Meta(OssClientSideEncryptionPartSize, strconv.FormatInt(cryptoContext.PartSize, 10)))
- imur, err = bucket.Bucket.InitiateMultipartUpload(objectKey, opts...)
- if err == nil {
- cryptoContext.ContentCipher = cc
- }
- return imur, err
- }
- // UploadPart uploads parts to oss, the part data are encrypted automaticly on client side
- // cryptoContext is the input parameter
- func (bucket CryptoBucket) UploadPart(imur oss.InitiateMultipartUploadResult, reader io.Reader,
- partSize int64, partNumber int, cryptoContext PartCryptoContext, options ...oss.Option) (oss.UploadPart, error) {
- options = bucket.AddEncryptionUaSuffix(options)
- var uploadPart oss.UploadPart
- if cryptoContext.ContentCipher == nil {
- return uploadPart, fmt.Errorf("error,cryptoContext is nil or cryptoContext.ContentCipher is nil")
- }
- if partNumber < 1 {
- return uploadPart, fmt.Errorf("partNumber:%d is smaller than 1", partNumber)
- }
- if cryptoContext.PartSize%int64(cryptoContext.ContentCipher.GetAlignLen()) != 0 {
- return uploadPart, fmt.Errorf("PartCryptoContext's PartSize must be aligned to %d", cryptoContext.ContentCipher.GetAlignLen())
- }
- cipherData := cryptoContext.ContentCipher.GetCipherData().Clone()
- // caclulate iv based on part number
- if partNumber > 1 {
- cipherData.SeekIV(uint64(partNumber-1) * uint64(cryptoContext.PartSize))
- }
- // for parallel upload part
- partCC, _ := cryptoContext.ContentCipher.Clone(cipherData)
- cryptoReader, err := partCC.EncryptContent(reader)
- if err != nil {
- return uploadPart, err
- }
- request := &oss.UploadPartRequest{
- InitResult: &imur,
- Reader: cryptoReader,
- PartSize: partCC.GetEncryptedLen(partSize),
- PartNumber: partNumber,
- }
- opts := addCryptoHeaders(options, partCC.GetCipherData())
- if cryptoContext.DataSize > 0 {
- opts = append(opts, oss.Meta(OssClientSideEncryptionDataSize, strconv.FormatInt(cryptoContext.DataSize, 10)))
- }
- opts = append(opts, oss.Meta(OssClientSideEncryptionPartSize, strconv.FormatInt(cryptoContext.PartSize, 10)))
- result, err := bucket.Bucket.DoUploadPart(request, opts)
- return result.Part, err
- }
- // UploadPartFromFile uploads part from the file, the part data are encrypted automaticly on client side
- // cryptoContext is the input parameter
- func (bucket CryptoBucket) UploadPartFromFile(imur oss.InitiateMultipartUploadResult, filePath string,
- startPosition, partSize int64, partNumber int, cryptoContext PartCryptoContext, options ...oss.Option) (oss.UploadPart, error) {
- options = bucket.AddEncryptionUaSuffix(options)
- var uploadPart = oss.UploadPart{}
- if cryptoContext.ContentCipher == nil {
- return uploadPart, fmt.Errorf("error,cryptoContext is nil or cryptoContext.ContentCipher is nil")
- }
- if cryptoContext.PartSize%int64(cryptoContext.ContentCipher.GetAlignLen()) != 0 {
- return uploadPart, fmt.Errorf("PartCryptoContext's PartSize must be aligned to %d", cryptoContext.ContentCipher.GetAlignLen())
- }
- fd, err := os.Open(filePath)
- if err != nil {
- return uploadPart, err
- }
- defer fd.Close()
- fd.Seek(startPosition, os.SEEK_SET)
- if partNumber < 1 {
- return uploadPart, fmt.Errorf("partNumber:%d is smaller than 1", partNumber)
- }
- cipherData := cryptoContext.ContentCipher.GetCipherData().Clone()
- // calculate iv based on part number
- if partNumber > 1 {
- cipherData.SeekIV(uint64(partNumber-1) * uint64(cryptoContext.PartSize))
- }
- // for parallel upload part
- partCC, _ := cryptoContext.ContentCipher.Clone(cipherData)
- cryptoReader, err := partCC.EncryptContent(fd)
- if err != nil {
- return uploadPart, err
- }
- encryptedLen := partCC.GetEncryptedLen(partSize)
- opts := addCryptoHeaders(options, partCC.GetCipherData())
- if cryptoContext.DataSize > 0 {
- opts = append(opts, oss.Meta(OssClientSideEncryptionDataSize, strconv.FormatInt(cryptoContext.DataSize, 10)))
- }
- opts = append(opts, oss.Meta(OssClientSideEncryptionPartSize, strconv.FormatInt(cryptoContext.PartSize, 10)))
- request := &oss.UploadPartRequest{
- InitResult: &imur,
- Reader: cryptoReader,
- PartSize: encryptedLen,
- PartNumber: partNumber,
- }
- result, err := bucket.Bucket.DoUploadPart(request, opts)
- return result.Part, err
- }
- // UploadPartCopy uploads part copy
- func (bucket CryptoBucket) UploadPartCopy(imur oss.InitiateMultipartUploadResult, srcBucketName, srcObjectKey string,
- startPosition, partSize int64, partNumber int, cryptoContext PartCryptoContext, options ...oss.Option) (oss.UploadPart, error) {
- var uploadPart = oss.UploadPart{}
- return uploadPart, fmt.Errorf("CryptoBucket doesn't support UploadPartCopy")
- }
|