github.com/lusis/distribution@v2.0.1+incompatible/registry/handlers/hmac.go (about) 1 package handlers 2 3 import ( 4 "crypto/hmac" 5 "crypto/sha256" 6 "encoding/base64" 7 "encoding/json" 8 "fmt" 9 "time" 10 ) 11 12 // layerUploadState captures the state serializable state of the layer upload. 13 type layerUploadState struct { 14 // name is the primary repository under which the layer will be linked. 15 Name string 16 17 // UUID identifies the upload. 18 UUID string 19 20 // offset contains the current progress of the upload. 21 Offset int64 22 23 // StartedAt is the original start time of the upload. 24 StartedAt time.Time 25 } 26 27 type hmacKey string 28 29 // unpackUploadState unpacks and validates the layer upload state from the 30 // token, using the hmacKey secret. 31 func (secret hmacKey) unpackUploadState(token string) (layerUploadState, error) { 32 var state layerUploadState 33 34 tokenBytes, err := base64.URLEncoding.DecodeString(token) 35 if err != nil { 36 return state, err 37 } 38 mac := hmac.New(sha256.New, []byte(secret)) 39 40 if len(tokenBytes) < mac.Size() { 41 return state, fmt.Errorf("Invalid token") 42 } 43 44 macBytes := tokenBytes[:mac.Size()] 45 messageBytes := tokenBytes[mac.Size():] 46 47 mac.Write(messageBytes) 48 if !hmac.Equal(mac.Sum(nil), macBytes) { 49 return state, fmt.Errorf("Invalid token") 50 } 51 52 if err := json.Unmarshal(messageBytes, &state); err != nil { 53 return state, err 54 } 55 56 return state, nil 57 } 58 59 // packUploadState packs the upload state signed with and hmac digest using 60 // the hmacKey secret, encoding to url safe base64. The resulting token can be 61 // used to share data with minimized risk of external tampering. 62 func (secret hmacKey) packUploadState(lus layerUploadState) (string, error) { 63 mac := hmac.New(sha256.New, []byte(secret)) 64 p, err := json.Marshal(lus) 65 if err != nil { 66 return "", err 67 } 68 69 mac.Write(p) 70 71 return base64.URLEncoding.EncodeToString(append(mac.Sum(nil), p...)), nil 72 }