9 "github.com/aliyun/aliyun-oss-go-sdk/oss"
12 // PartCryptoContext save encryption or decryption information
13 type PartCryptoContext struct {
14 ContentCipher ContentCipher
19 // Valid judge PartCryptoContext is valid or not
20 func (pcc PartCryptoContext) Valid() bool {
21 if pcc.ContentCipher == nil || pcc.DataSize == 0 || pcc.PartSize == 0 {
27 // InitiateMultipartUpload initializes multipart upload for client encryption
28 // cryptoContext.PartSize and cryptoContext.DataSize are input parameter
29 // cryptoContext.PartSize must aligned to the secret iv length
30 // cryptoContext.ContentCipher is output parameter
31 // cryptoContext will be used in next API
32 func (bucket CryptoBucket) InitiateMultipartUpload(objectKey string, cryptoContext *PartCryptoContext, options ...oss.Option) (oss.InitiateMultipartUploadResult, error) {
33 options = bucket.AddEncryptionUaSuffix(options)
34 var imur oss.InitiateMultipartUploadResult
35 if cryptoContext == nil {
36 return imur, fmt.Errorf("error,cryptoContext is nil")
39 if cryptoContext.PartSize <= 0 {
40 return imur, fmt.Errorf("invalid PartCryptoContext's PartSize %d", cryptoContext.PartSize)
43 cc, err := bucket.ContentCipherBuilder.ContentCipher()
48 if cryptoContext.PartSize%int64(cc.GetAlignLen()) != 0 {
49 return imur, fmt.Errorf("PartCryptoContext's PartSize must be aligned to %d", cc.GetAlignLen())
52 opts := addCryptoHeaders(options, cc.GetCipherData())
53 if cryptoContext.DataSize > 0 {
54 opts = append(opts, oss.Meta(OssClientSideEncryptionDataSize, strconv.FormatInt(cryptoContext.DataSize, 10)))
56 opts = append(opts, oss.Meta(OssClientSideEncryptionPartSize, strconv.FormatInt(cryptoContext.PartSize, 10)))
58 imur, err = bucket.Bucket.InitiateMultipartUpload(objectKey, opts...)
60 cryptoContext.ContentCipher = cc
65 // UploadPart uploads parts to oss, the part data are encrypted automaticly on client side
66 // cryptoContext is the input parameter
67 func (bucket CryptoBucket) UploadPart(imur oss.InitiateMultipartUploadResult, reader io.Reader,
68 partSize int64, partNumber int, cryptoContext PartCryptoContext, options ...oss.Option) (oss.UploadPart, error) {
69 options = bucket.AddEncryptionUaSuffix(options)
70 var uploadPart oss.UploadPart
71 if cryptoContext.ContentCipher == nil {
72 return uploadPart, fmt.Errorf("error,cryptoContext is nil or cryptoContext.ContentCipher is nil")
76 return uploadPart, fmt.Errorf("partNumber:%d is smaller than 1", partNumber)
79 if cryptoContext.PartSize%int64(cryptoContext.ContentCipher.GetAlignLen()) != 0 {
80 return uploadPart, fmt.Errorf("PartCryptoContext's PartSize must be aligned to %d", cryptoContext.ContentCipher.GetAlignLen())
83 cipherData := cryptoContext.ContentCipher.GetCipherData().Clone()
84 // caclulate iv based on part number
86 cipherData.SeekIV(uint64(partNumber-1) * uint64(cryptoContext.PartSize))
89 // for parallel upload part
90 partCC, _ := cryptoContext.ContentCipher.Clone(cipherData)
92 cryptoReader, err := partCC.EncryptContent(reader)
94 return uploadPart, err
97 request := &oss.UploadPartRequest{
100 PartSize: partCC.GetEncryptedLen(partSize),
101 PartNumber: partNumber,
104 opts := addCryptoHeaders(options, partCC.GetCipherData())
105 if cryptoContext.DataSize > 0 {
106 opts = append(opts, oss.Meta(OssClientSideEncryptionDataSize, strconv.FormatInt(cryptoContext.DataSize, 10)))
108 opts = append(opts, oss.Meta(OssClientSideEncryptionPartSize, strconv.FormatInt(cryptoContext.PartSize, 10)))
110 result, err := bucket.Bucket.DoUploadPart(request, opts)
111 return result.Part, err
114 // UploadPartFromFile uploads part from the file, the part data are encrypted automaticly on client side
115 // cryptoContext is the input parameter
116 func (bucket CryptoBucket) UploadPartFromFile(imur oss.InitiateMultipartUploadResult, filePath string,
117 startPosition, partSize int64, partNumber int, cryptoContext PartCryptoContext, options ...oss.Option) (oss.UploadPart, error) {
118 options = bucket.AddEncryptionUaSuffix(options)
119 var uploadPart = oss.UploadPart{}
120 if cryptoContext.ContentCipher == nil {
121 return uploadPart, fmt.Errorf("error,cryptoContext is nil or cryptoContext.ContentCipher is nil")
124 if cryptoContext.PartSize%int64(cryptoContext.ContentCipher.GetAlignLen()) != 0 {
125 return uploadPart, fmt.Errorf("PartCryptoContext's PartSize must be aligned to %d", cryptoContext.ContentCipher.GetAlignLen())
128 fd, err := os.Open(filePath)
130 return uploadPart, err
133 fd.Seek(startPosition, os.SEEK_SET)
136 return uploadPart, fmt.Errorf("partNumber:%d is smaller than 1", partNumber)
139 cipherData := cryptoContext.ContentCipher.GetCipherData().Clone()
140 // calculate iv based on part number
142 cipherData.SeekIV(uint64(partNumber-1) * uint64(cryptoContext.PartSize))
145 // for parallel upload part
146 partCC, _ := cryptoContext.ContentCipher.Clone(cipherData)
147 cryptoReader, err := partCC.EncryptContent(fd)
149 return uploadPart, err
152 encryptedLen := partCC.GetEncryptedLen(partSize)
153 opts := addCryptoHeaders(options, partCC.GetCipherData())
154 if cryptoContext.DataSize > 0 {
155 opts = append(opts, oss.Meta(OssClientSideEncryptionDataSize, strconv.FormatInt(cryptoContext.DataSize, 10)))
157 opts = append(opts, oss.Meta(OssClientSideEncryptionPartSize, strconv.FormatInt(cryptoContext.PartSize, 10)))
159 request := &oss.UploadPartRequest{
161 Reader: cryptoReader,
162 PartSize: encryptedLen,
163 PartNumber: partNumber,
165 result, err := bucket.Bucket.DoUploadPart(request, opts)
166 return result.Part, err
169 // UploadPartCopy uploads part copy
170 func (bucket CryptoBucket) UploadPartCopy(imur oss.InitiateMultipartUploadResult, srcBucketName, srcObjectKey string,
171 startPosition, partSize int64, partNumber int, cryptoContext PartCryptoContext, options ...oss.Option) (oss.UploadPart, error) {
172 var uploadPart = oss.UploadPart{}
173 return uploadPart, fmt.Errorf("CryptoBucket doesn't support UploadPartCopy")