我们在需要存储文件的数据落盘加密时,就会用到这种简单的服务端加密实现;
使用的前提是:
- S3存储服务端支持https;
- S3存储服务端实现了AES256加密
下面我们以go的aws sdk来进行举例,本例是访问私有签发证书的服务:
import (
"bytes"
"context"
"crypto/md5"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
credentials2 "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/minio/minio-go/v7/pkg/encrypt"
"io"
"io/ioutil"
"net"
"net/http"
"time"
)
var(
ak = "accessKeyValue" //文件服务分配的账号
sk = "secretKeyValue" //文件服务分配的秘钥
endPoint = "https://127.0.0.1:9000" // 存储服务的地址
region = "default" //适用范围
svc *s3.S3 // aws s3 的client
iamSvc *iam.IAM
uploader *s3manager.Uploader
s3Client *minio.Client // minio s3的client
)
func Init(){
cres := credentials2.NewStaticCredentials(ak, sk, "")
cfg := aws.NewConfig().WithRegion(region).WithEndpoint(endPoint).WithCredentials(cres).WithS3ForcePathStyle(
true).WithMaxRetries(0).WithDisableSSL(true)
// 这段代码就是跳过证书校验,不然会报X509的错误
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
cfg.HTTPClient = &http.Client{
Transport: tr,
}
sess, err := session.NewSession(cfg)
if err != nil {
fmt.Println(err)
}
// sws S3 的client
svc = s3.New(sess)
iamSvc = iam.New(sess, cfg)
// minio 的client
s3Client, err = minio.New("127.0.0.1:9000", &minio.Options{
Creds: credentials.NewStaticV4(ak, sk, ""),
Secure: true,
Transport: tr,
})
if err != nil {
fmt.Println(err)
return
}
}
func main(){
Init()
t := time.Now()
bucketName := "test-ssec"
objectID := time.Now().Format("20060102150405")
createBucket(bucketName)
putSSECObject([]byte("2222-2222-2222-2222"), bucketName, "", objectID)
getSSECObject(bucketName,objectID)
putSSECObjectMinio([]byte("2222-2222-2222-2222"), bucketName, "", objectID)
fmt.Println(time.Since(t))
}
// 创建bucket
func createBucket(bucketName string) {
input := &s3.CreateBucketInput{
Bucket: aws.String(bucketName),
}
result, err := svc.CreateBucket(input)
fmt.Printf("CreateBucket %v \n", result)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case s3.ErrCodeBucketAlreadyExists:
fmt.Println(s3.ErrCodeBucketAlreadyExists, aerr.Error())
case s3.ErrCodeBucketAlreadyOwnedByYou:
fmt.Println(s3.ErrCodeBucketAlreadyOwnedByYou, aerr.Error())
default:
fmt.Println(aerr.Error())
}
} else {
fmt.Println(err.Error())
}
}
}
// aws s3 client 通过SSE-C 的方式上传文件
func putSSECObject(dataImage []byte, bucketName, contentType, objectID string){
t := time.Now()
inputObject := &s3.PutObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectID),
ContentType: aws.String(contentType),
Body: bytes.NewReader(dataImage),
ContentLength: aws.Int64(int64(len(dataImage))),
// 目前只支持 AES256
SSECustomerAlgorithm: aws.String("AES256"),
// 秘钥的是32位的字符串(下面的是 32byteslongsecretkeymustprovided aws会帮我们做base64编码)
SSECustomerKey: aws.String("32byteslongsecretkeymustprovided"),
// 原始秘钥的MD5值,切记是base64之前的秘钥
SSECustomerKeyMD5: aws.String("7PpPLAK26ONlVUGOWlusfg=="),
}
fmt.Println(int64(len(dataImage)))
resp, err := svc.PutObject(inputObject)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("upload resp: %v cost time : %v \n",resp, time.Since(t))
}
// aws s3 client 通过SSE-C 的方式下载文件
func getSSECObject(bucketName, objectID string){
t := time.Now()
inputObject := &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectID),
// 目前只支持 AES256
SSECustomerAlgorithm: aws.String("AES256"),
// 秘钥的256位base64编码的字符串(下面的是 32byteslongsecretkeymustprovided 做了base64编码)
SSECustomerKey: aws.String("32byteslongsecretkeymustprovided"),
// 原始秘钥的MD5值,切记是base64之前的秘钥
SSECustomerKeyMD5: aws.String("7PpPLAK26ONlVUGOWlusfg=="),
}
resp, err := svc.GetObject(inputObject)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("get resp: %v cost time : %v \n",resp, time.Since(t))
res, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(string(res))
}
// minio client 上传文件
func putSSECObjectMinio(dataImage []byte, bucketName, contentType, objectID string){
sse,_ := encrypt.NewSSEC([]byte("32byteslongsecretkeymustprovided"))
resp, err := s3Client.PutObject(context.Background(), bucketName,objectID,bytes.NewReader(dataImage),
int64(len(dataImage)),
minio.PutObjectOptions{
ServerSideEncryption: sse,
})
if err != nil {
fmt.Printf("putSSECObjectMinio err : %v \n" ,err)
}
fmt.Printf("putSSECObjectMinio %v\n", resp)
}