1/* 2 Copyright The ocicrypt Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15*/ 16 17package blockcipher 18 19import ( 20 "io" 21 22 "github.com/opencontainers/go-digest" 23 "github.com/pkg/errors" 24) 25 26// LayerCipherType is the ciphertype as specified in the layer metadata 27type LayerCipherType string 28 29// TODO: Should be obtained from OCI spec once included 30const ( 31 AES256CTR LayerCipherType = "AES_256_CTR_HMAC_SHA256" 32) 33 34// PrivateLayerBlockCipherOptions includes the information required to encrypt/decrypt 35// an image which are sensitive and should not be in plaintext 36type PrivateLayerBlockCipherOptions struct { 37 // SymmetricKey represents the symmetric key used for encryption/decryption 38 // This field should be populated by Encrypt/Decrypt calls 39 SymmetricKey []byte `json:"symkey"` 40 41 // Digest is the digest of the original data for verification. 42 // This is NOT populated by Encrypt/Decrypt calls 43 Digest digest.Digest `json:"digest"` 44 45 // CipherOptions contains the cipher metadata used for encryption/decryption 46 // This field should be populated by Encrypt/Decrypt calls 47 CipherOptions map[string][]byte `json:"cipheroptions"` 48} 49 50// PublicLayerBlockCipherOptions includes the information required to encrypt/decrypt 51// an image which are public and can be deduplicated in plaintext across multiple 52// recipients 53type PublicLayerBlockCipherOptions struct { 54 // CipherType denotes the cipher type according to the list of OCI suppported 55 // cipher types. 56 CipherType LayerCipherType `json:"cipher"` 57 58 // Hmac contains the hmac string to help verify encryption 59 Hmac []byte `json:"hmac"` 60 61 // CipherOptions contains the cipher metadata used for encryption/decryption 62 // This field should be populated by Encrypt/Decrypt calls 63 CipherOptions map[string][]byte `json:"cipheroptions"` 64} 65 66// LayerBlockCipherOptions contains the public and private LayerBlockCipherOptions 67// required to encrypt/decrypt an image 68type LayerBlockCipherOptions struct { 69 Public PublicLayerBlockCipherOptions 70 Private PrivateLayerBlockCipherOptions 71} 72 73// LayerBlockCipher returns a provider for encrypt/decrypt functionality 74// for handling the layer data for a specific algorithm 75type LayerBlockCipher interface { 76 // GenerateKey creates a symmetric key 77 GenerateKey() ([]byte, error) 78 // Encrypt takes in layer data and returns the ciphertext and relevant LayerBlockCipherOptions 79 Encrypt(layerDataReader io.Reader, opt LayerBlockCipherOptions) (io.Reader, Finalizer, error) 80 // Decrypt takes in layer ciphertext data and returns the plaintext and relevant LayerBlockCipherOptions 81 Decrypt(layerDataReader io.Reader, opt LayerBlockCipherOptions) (io.Reader, LayerBlockCipherOptions, error) 82} 83 84// LayerBlockCipherHandler is the handler for encrypt/decrypt for layers 85type LayerBlockCipherHandler struct { 86 cipherMap map[LayerCipherType]LayerBlockCipher 87} 88 89// Finalizer is called after data blobs are written, and returns the LayerBlockCipherOptions for the encrypted blob 90type Finalizer func() (LayerBlockCipherOptions, error) 91 92// GetOpt returns the value of the cipher option and if the option exists 93func (lbco LayerBlockCipherOptions) GetOpt(key string) (value []byte, ok bool) { 94 if v, ok := lbco.Public.CipherOptions[key]; ok { 95 return v, ok 96 } else if v, ok := lbco.Private.CipherOptions[key]; ok { 97 return v, ok 98 } else { 99 return nil, false 100 } 101} 102 103func wrapFinalizerWithType(fin Finalizer, typ LayerCipherType) Finalizer { 104 return func() (LayerBlockCipherOptions, error) { 105 lbco, err := fin() 106 if err != nil { 107 return LayerBlockCipherOptions{}, err 108 } 109 lbco.Public.CipherType = typ 110 return lbco, err 111 } 112} 113 114// Encrypt is the handler for the layer decryption routine 115func (h *LayerBlockCipherHandler) Encrypt(plainDataReader io.Reader, typ LayerCipherType) (io.Reader, Finalizer, error) { 116 if c, ok := h.cipherMap[typ]; ok { 117 sk, err := c.GenerateKey() 118 if err != nil { 119 return nil, nil, err 120 } 121 opt := LayerBlockCipherOptions{ 122 Private: PrivateLayerBlockCipherOptions{ 123 SymmetricKey: sk, 124 }, 125 } 126 encDataReader, fin, err := c.Encrypt(plainDataReader, opt) 127 if err == nil { 128 fin = wrapFinalizerWithType(fin, typ) 129 } 130 return encDataReader, fin, err 131 } 132 return nil, nil, errors.Errorf("unsupported cipher type: %s", typ) 133} 134 135// Decrypt is the handler for the layer decryption routine 136func (h *LayerBlockCipherHandler) Decrypt(encDataReader io.Reader, opt LayerBlockCipherOptions) (io.Reader, LayerBlockCipherOptions, error) { 137 typ := opt.Public.CipherType 138 if typ == "" { 139 return nil, LayerBlockCipherOptions{}, errors.New("no cipher type provided") 140 } 141 if c, ok := h.cipherMap[LayerCipherType(typ)]; ok { 142 return c.Decrypt(encDataReader, opt) 143 } 144 return nil, LayerBlockCipherOptions{}, errors.Errorf("unsupported cipher type: %s", typ) 145} 146 147// NewLayerBlockCipherHandler returns a new default handler 148func NewLayerBlockCipherHandler() (*LayerBlockCipherHandler, error) { 149 h := LayerBlockCipherHandler{ 150 cipherMap: map[LayerCipherType]LayerBlockCipher{}, 151 } 152 153 var err error 154 h.cipherMap[AES256CTR], err = NewAESCTRLayerBlockCipher(256) 155 if err != nil { 156 return nil, errors.Wrap(err, "unable to set up Cipher AES-256-CTR") 157 } 158 159 return &h, nil 160} 161