decryption_client.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package s3crypto
  2. import (
  3. "github.com/aws/aws-sdk-go/aws/client"
  4. "github.com/aws/aws-sdk-go/aws/request"
  5. "github.com/aws/aws-sdk-go/service/kms"
  6. "github.com/aws/aws-sdk-go/service/s3"
  7. "github.com/aws/aws-sdk-go/service/s3/s3iface"
  8. )
  9. // WrapEntry is builder that return a proper key decrypter and error
  10. type WrapEntry func(Envelope) (CipherDataDecrypter, error)
  11. // CEKEntry is a builder thatn returns a proper content decrypter and error
  12. type CEKEntry func(CipherData) (ContentCipher, error)
  13. // DecryptionClient is an S3 crypto client. By default the SDK will use Authentication mode which
  14. // will use KMS for key wrapping and AES GCM for content encryption.
  15. // AES GCM will load all data into memory. However, the rest of the content algorithms
  16. // do not load the entire contents into memory.
  17. type DecryptionClient struct {
  18. S3Client s3iface.S3API
  19. // LoadStrategy is used to load the metadata either from the metadata of the object
  20. // or from a separate file in s3.
  21. //
  22. // Defaults to our default load strategy.
  23. LoadStrategy LoadStrategy
  24. WrapRegistry map[string]WrapEntry
  25. CEKRegistry map[string]CEKEntry
  26. }
  27. // NewDecryptionClient instantiates a new S3 crypto client
  28. //
  29. // Example:
  30. // cmkID := "some key id to kms"
  31. // sess := session.New()
  32. // handler, err = s3crypto.NewKMSEncryptHandler(sess, cmkID, s3crypto.MaterialDescription{})
  33. // if err != nil {
  34. // return err
  35. // }
  36. // svc := s3crypto.New(sess, s3crypto.AESGCMContentCipherBuilder(handler))
  37. func NewDecryptionClient(prov client.ConfigProvider, options ...func(*DecryptionClient)) *DecryptionClient {
  38. s3client := s3.New(prov)
  39. client := &DecryptionClient{
  40. S3Client: s3client,
  41. LoadStrategy: defaultV2LoadStrategy{
  42. client: s3client,
  43. },
  44. WrapRegistry: map[string]WrapEntry{
  45. KMSWrap: (kmsKeyHandler{
  46. kms: kms.New(prov),
  47. }).decryptHandler,
  48. },
  49. CEKRegistry: map[string]CEKEntry{
  50. AESGCMNoPadding: newAESGCMContentCipher,
  51. },
  52. }
  53. for _, option := range options {
  54. option(client)
  55. }
  56. return client
  57. }
  58. // GetObjectRequest will make a request to s3 and retrieve the object. In this process
  59. // decryption will be done. The SDK only supports V2 reads of KMS and GCM.
  60. //
  61. // Example:
  62. // svc := s3crypto.New(session.New(),s3crypto.AESGCMContentCipherBuilder(handler))
  63. // req, out := svc.GetObjectRequest(&s3.GetObjectInput {
  64. // Key: aws.String("testKey"),
  65. // Bucket: aws.String("testBucket"),
  66. // })
  67. // err := req.Send()
  68. func (c *DecryptionClient) GetObjectRequest(input *s3.GetObjectInput) (*request.Request, *s3.GetObjectOutput) {
  69. req, out := c.S3Client.GetObjectRequest(input)
  70. req.Handlers.Unmarshal.PushBack(func(r *request.Request) {
  71. env, err := c.LoadStrategy.Load(r)
  72. if err != nil {
  73. r.Error = err
  74. out.Body.Close()
  75. return
  76. }
  77. // If KMS should return the correct CEK algorithm with the proper
  78. // KMS key provider
  79. cipher, err := c.contentCipherFromEnvelope(env)
  80. if err != nil {
  81. r.Error = err
  82. out.Body.Close()
  83. return
  84. }
  85. reader, err := cipher.DecryptContents(out.Body)
  86. if err != nil {
  87. r.Error = err
  88. out.Body.Close()
  89. return
  90. }
  91. out.Body = reader
  92. })
  93. return req, out
  94. }
  95. // GetObject is a wrapper for GetObjectRequest
  96. func (c *DecryptionClient) GetObject(input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
  97. req, out := c.GetObjectRequest(input)
  98. return out, req.Send()
  99. }