AWS-SDK-GO 通过SSE-C服务端加密存储

2022-03-25  本文已影响0人  时彬斌

我们在需要存储文件的数据落盘加密时,就会用到这种简单的服务端加密实现;
使用的前提是:

  1. S3存储服务端支持https;
  2. 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)
}

上一篇下一篇

猜你喜欢

热点阅读