diff --git a/cos.go b/cos.go index a09b62f..e15a382 100644 --- a/cos.go +++ b/cos.go @@ -22,7 +22,7 @@ import ( const ( // Version current go sdk version - Version = "0.7.25" + Version = "0.7.26" userAgent = "cos-go-sdk-v5/" + Version contentTypeXML = "application/xml" defaultServiceBaseURL = "http://service.cos.myqcloud.com" diff --git a/crypto/crypto_object.go b/crypto/crypto_object.go index 7c8f1f7..8566faa 100644 --- a/crypto/crypto_object.go +++ b/crypto/crypto_object.go @@ -2,6 +2,7 @@ package coscrypto import ( "context" + "encoding/base64" "fmt" "github.com/tencentyun/cos-go-sdk-v5" "io" @@ -107,7 +108,10 @@ func (s *CryptoObjectService) Get(ctx context.Context, name string, opt *cos.Obj return s.ObjectService.Get(ctx, name, opt, id...) } - envelope := getEnvelopeFromHeader(&meta.Header) + envelope, err := getEnvelopeFromHeader(&meta.Header) + if err != nil { + return nil, err + } if !envelope.IsValid() { return nil, fmt.Errorf("get envelope from header failed, object:%v", name) } @@ -208,20 +212,39 @@ func addCryptoHeaders(header *http.Header, cd *CipherData) { if cd.MatDesc != "" { header.Add(COSClientSideEncryptionMatDesc, cd.MatDesc) } - header.Add(COSClientSideEncryptionKey, string(cd.EncryptedKey)) - header.Add(COSClientSideEncryptionStart, string(cd.EncryptedIV)) + // encrypted key + strEncryptedKey := base64.StdEncoding.EncodeToString(cd.EncryptedKey) + header.Add(COSClientSideEncryptionKey, strEncryptedKey) + + // encrypted iv + strEncryptedIV := base64.StdEncoding.EncodeToString(cd.EncryptedIV) + header.Add(COSClientSideEncryptionStart, strEncryptedIV) + header.Add(COSClientSideEncryptionWrapAlg, cd.WrapAlgorithm) header.Add(COSClientSideEncryptionCekAlg, cd.CEKAlgorithm) } -func getEnvelopeFromHeader(header *http.Header) Envelope { +func getEnvelopeFromHeader(header *http.Header) (Envelope, error) { var envelope Envelope + envelope.CipherKey = header.Get(COSClientSideEncryptionKey) + decodedKey, err := base64.StdEncoding.DecodeString(envelope.CipherKey) + if err != nil { + return envelope, err + } + envelope.CipherKey = string(decodedKey) + envelope.IV = header.Get(COSClientSideEncryptionStart) + decodedIV, err := base64.StdEncoding.DecodeString(envelope.IV) + if err != nil { + return envelope, err + } + envelope.IV = string(decodedIV) + envelope.MatDesc = header.Get(COSClientSideEncryptionMatDesc) envelope.WrapAlg = header.Get(COSClientSideEncryptionWrapAlg) envelope.CEKAlg = header.Get(COSClientSideEncryptionCekAlg) - return envelope + return envelope, nil } func isEncrypted(header *http.Header) bool { diff --git a/crypto/crypto_object_part_test.go b/crypto/crypto_object_part_test.go index 75a05f5..c9af052 100644 --- a/crypto/crypto_object_part_test.go +++ b/crypto/crypto_object_part_test.go @@ -104,10 +104,14 @@ func (s *CosTestSuite) TestMultiUpload_DecryptWithKey() { resp, err = s.CClient.Object.Head(context.Background(), name, nil) assert.Nil(s.T(), err, "HeadObject Failed") cipherKey := resp.Header.Get(coscrypto.COSClientSideEncryptionKey) + cipherKeybs, err := base64.StdEncoding.DecodeString(cipherKey) + assert.Nil(s.T(), err, "base64 Decode Failed") cipherIV := resp.Header.Get(coscrypto.COSClientSideEncryptionStart) - key, err := s.Master.Decrypt([]byte(cipherKey)) + cipherIVbs, err := base64.StdEncoding.DecodeString(cipherIV) + assert.Nil(s.T(), err, "base64 Decode Failed") + key, err := s.Master.Decrypt(cipherKeybs) assert.Nil(s.T(), err, "Master Decrypt Failed") - iv, err := s.Master.Decrypt([]byte(cipherIV)) + iv, err := s.Master.Decrypt(cipherIVbs) assert.Nil(s.T(), err, "Master Decrypt Failed") // 手动解密 diff --git a/crypto/crypto_object_test.go b/crypto/crypto_object_test.go index a662c71..b95c27e 100644 --- a/crypto/crypto_object_test.go +++ b/crypto/crypto_object_test.go @@ -75,10 +75,14 @@ func (s *CosTestSuite) TestPutGetDeleteObject_DecryptWithKey_10MB() { resp, err := s.CClient.Object.Head(context.Background(), name, nil) assert.Nil(s.T(), err, "HeadObject Failed") cipherKey := resp.Header.Get(coscrypto.COSClientSideEncryptionKey) + cipherKeybs, err := base64.StdEncoding.DecodeString(cipherKey) + assert.Nil(s.T(), err, "base64 Decode Failed") cipherIV := resp.Header.Get(coscrypto.COSClientSideEncryptionStart) - key, err := s.Master.Decrypt([]byte(cipherKey)) + cipherIVbs, err := base64.StdEncoding.DecodeString(cipherIV) + assert.Nil(s.T(), err, "base64 Decode Failed") + key, err := s.Master.Decrypt(cipherKeybs) assert.Nil(s.T(), err, "Master Decrypt Failed") - iv, err := s.Master.Decrypt([]byte(cipherIV)) + iv, err := s.Master.Decrypt(cipherIVbs) assert.Nil(s.T(), err, "Master Decrypt Failed") // 正常读取 diff --git a/crypto/master_kms_cipher.go b/crypto/master_kms_cipher.go index 011458e..2a49335 100644 --- a/crypto/master_kms_cipher.go +++ b/crypto/master_kms_cipher.go @@ -64,6 +64,7 @@ func (kc *MasterKMSCipher) Encrypt(plaintext []byte) ([]byte, error) { if err != nil { return nil, err } + // https://cloud.tencent.com/document/product/573/34420 文档有误,返回的结果并没有base64编码 return []byte(*resp.Response.CiphertextBlob), nil } diff --git a/example/crypto/crypto_sample.go b/example/crypto/crypto_sample.go index 925c43f..7ea43c0 100644 --- a/example/crypto/crypto_sample.go +++ b/example/crypto/crypto_sample.go @@ -39,6 +39,13 @@ func log_status(err error) { os.Exit(1) } +func cos_max(x, y int64) int64 { + if x > y { + return x + } + return y +} + func simple_put_object() { u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -196,7 +203,7 @@ func multi_put_object() { cryptoCtx := coscrypto.CryptoContext{ DataSize: contentLength, // 每个分块需要16字节对齐 - PartSize: (contentLength / 16 / 3) * 16, + PartSize: cos_max(1024*1024, (contentLength/16/3)*16), } v, _, err := client.Object.InitiateMultipartUpload(context.Background(), name, nil, &cryptoCtx) log_status(err) @@ -268,7 +275,7 @@ func multi_put_object_from_file() { cryptoCtx := coscrypto.CryptoContext{ DataSize: contentLength, // 每个分块需要16字节对齐 - PartSize: (contentLength / 16 / 3) * 16, + PartSize: cos_max(1024*1024, (contentLength/16/3)*16), } // 切分数据 _, chunks, _, err := cos.SplitFileIntoChunks(filepath, cryptoCtx.PartSize) diff --git a/object.go b/object.go index 078b92d..5d7fed2 100644 --- a/object.go +++ b/object.go @@ -768,6 +768,9 @@ func SplitFileIntoChunks(filePath string, partSize int64) (int64, []Chunk, int, } var partNum int64 if partSize > 0 { + if partSize < 1024*1024 { + return 0, nil, 0, errors.New("partSize>=1048576 is required") + } partNum = stat.Size() / partSize if partNum >= 10000 { return 0, nil, 0, errors.New("Too many parts, out of 10000") @@ -1066,6 +1069,9 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string func SplitSizeIntoChunks(totalBytes int64, partSize int64) ([]Chunk, int, error) { var partNum int64 if partSize > 0 { + if partSize < 1024*1024 { + return nil, 0, errors.New("partSize>=1048576 is required") + } partNum = totalBytes / partSize if partNum >= 10000 { return nil, 0, errors.New("Too manry parts, out of 10000")