github.com/zntrio/harp/v2@v2.0.9/pkg/container/seal/v1/helpers.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package v1 19 20 import ( 21 "bytes" 22 "errors" 23 "fmt" 24 "io" 25 26 "github.com/awnumar/memguard" 27 "google.golang.org/protobuf/proto" 28 29 containerv1 "github.com/zntrio/harp/v2/api/gen/go/harp/container/v1" 30 "github.com/zntrio/harp/v2/pkg/sdk/security" 31 32 "golang.org/x/crypto/blake2b" 33 "golang.org/x/crypto/nacl/box" 34 "golang.org/x/crypto/nacl/secretbox" 35 ) 36 37 func pskStretch(key, salt []byte) (*[preSharedKeySize]byte, error) { 38 pskh, err := blake2b.New512(key) 39 if err != nil { 40 return nil, fmt.Errorf("unable to prepare preshared key: %w", err) 41 } 42 pskh.Write(salt) 43 hashPsk := pskh.Sum(nil) 44 45 psk := &[preSharedKeySize]byte{} 46 copy(psk[:], hashPsk[:preSharedKeySize]) 47 48 return psk, nil 49 } 50 51 func deriveSharedKeyFromRecipient(publicKey, privateKey *[privateKeySize]byte, preSharedKey *[preSharedKeySize]byte) (*[encryptionKeySize]byte, error) { 52 // Prepare nonce 53 var nonce [nonceSize]byte 54 copy(nonce[:], "harp_derived_id_sboxkey0") 55 56 // Prepare payload 57 zero := make([]byte, 32) 58 memguard.WipeBytes(zero) 59 60 // Use box as a key agreement function 61 var sharedKey [encryptionKeySize]byte 62 derivedKey := box.Seal(nil, zero, &nonce, publicKey, privateKey) 63 copy(sharedKey[:], derivedKey[len(derivedKey)-encryptionKeySize:]) 64 65 // Apply psk, this will act as a second knowledge factor to allow container 66 // unseal 67 if preSharedKey != nil { 68 // Compute HMAC-Blakeb of the shared secret. 69 pskh, err := blake2b.New(encryptionKeySize, preSharedKey[:]) 70 if err != nil { 71 return nil, fmt.Errorf("unable to initialize PSK derivation: %w", err) 72 } 73 pskh.Write([]byte{0x00, 0x00, 0x00, 0x01}) 74 pskh.Write(sharedKey[:]) 75 skHash := pskh.Sum(nil) 76 copy(sharedKey[:], skHash[:encryptionKeySize]) 77 } 78 79 // No error 80 return &sharedKey, nil 81 } 82 83 func computeHeaderHash(headers *containerv1.Header) ([]byte, error) { 84 // Check arguments 85 if headers == nil { 86 return nil, errors.New("unable process with nil headers") 87 } 88 89 // Prepare signature 90 header, err := proto.Marshal(headers) 91 if err != nil { 92 return nil, fmt.Errorf("unable to marshal container headers") 93 } 94 95 // Hash serialized proto 96 hash := blake2b.Sum512(header) 97 98 // No error 99 return hash[:], nil 100 } 101 102 func computeProtectedHash(headerHash, content []byte) []byte { 103 // Prepare protected content 104 protected := bytes.Buffer{} 105 protected.Write([]byte(signatureDomainSeparation)) 106 protected.WriteByte(0x00) 107 protected.Write(headerHash) 108 contentHash := blake2b.Sum512(content) 109 protected.Write(contentHash[:]) 110 111 // No error 112 return protected.Bytes() 113 } 114 115 func packRecipient(rand io.Reader, payloadKey, ephPrivKey, peerPublicKey *[publicKeySize]byte, preSharedKey *[preSharedKeySize]byte) (*containerv1.Recipient, error) { 116 // Check arguments 117 if payloadKey == nil { 118 return nil, fmt.Errorf("unable to proceed with nil payload key") 119 } 120 if ephPrivKey == nil { 121 return nil, fmt.Errorf("unable to proceed with nil private key") 122 } 123 if peerPublicKey == nil { 124 return nil, fmt.Errorf("unable to proceed with nil public key") 125 } 126 127 // Create recipient key 128 recipientKey, err := deriveSharedKeyFromRecipient(peerPublicKey, ephPrivKey, preSharedKey) 129 if err != nil { 130 return nil, fmt.Errorf("unable to derive shared recipient encryption key: %w", err) 131 } 132 133 // Calculate identifier 134 identifier, err := keyIdentifierFromDerivedKey(recipientKey, preSharedKey) 135 if err != nil { 136 return nil, fmt.Errorf("unable to derive key identifier: %w", err) 137 } 138 139 // Generate recipient nonce 140 var recipientNonce [nonceSize]byte 141 if _, err := io.ReadFull(rand, recipientNonce[:]); err != nil { 142 return nil, fmt.Errorf("unable to generate recipient nonce for encryption") 143 } 144 145 // Pack recipient 146 recipient := &containerv1.Recipient{ 147 Identifier: identifier, 148 Key: secretbox.Seal(recipientNonce[:], payloadKey[:], &recipientNonce, recipientKey), 149 } 150 151 // Return recipient 152 return recipient, nil 153 } 154 155 func keyIdentifierFromDerivedKey(derivedKey *[encryptionKeySize]byte, preSharedKey *[preSharedKeySize]byte) ([]byte, error) { 156 // Hash the derived key 157 h, err := blake2b.New512([]byte("harp signcryption box key identifier")) 158 if err != nil { 159 return nil, fmt.Errorf("unable to generate recipient identifier hasher") 160 } 161 if _, err := h.Write(derivedKey[:]); err != nil { 162 return nil, fmt.Errorf("unable to generate recipient identifier") 163 } 164 165 // Apply psk if specified 166 if preSharedKey != nil { 167 if _, err := h.Write(preSharedKey[:]); err != nil { 168 return nil, fmt.Errorf("unable to generate recipient identifier") 169 } 170 } 171 172 // Return 32 bytes trucanted hash. 173 return h.Sum(nil)[0:keyIdentifierSize], nil 174 } 175 176 func tryRecipientKeys(derivedKey *[encryptionKeySize]byte, recipients []*containerv1.Recipient, preSharedKey *[preSharedKeySize]byte) ([]byte, error) { 177 // Calculate recipient identifier 178 identifier, err := keyIdentifierFromDerivedKey(derivedKey, preSharedKey) 179 if err != nil { 180 return nil, fmt.Errorf("unable to generate identifier: %w", err) 181 } 182 183 // Find matching recipient 184 for _, r := range recipients { 185 // Check recipient identifiers 186 if !security.SecureCompare(identifier, r.Identifier) { 187 continue 188 } 189 190 var nonce [nonceSize]byte 191 copy(nonce[:], r.Key[:nonceSize]) 192 193 // Try to decrypt the secretbox with the derived key. 194 payloadKey, isValid := secretbox.Open(nil, r.Key[nonceSize:], &nonce, derivedKey) 195 if !isValid { 196 return nil, fmt.Errorf("invalid recipient encryption key") 197 } 198 199 // Encryption key found, return no error. 200 return payloadKey, nil 201 } 202 203 // No recipient found in list. 204 return nil, fmt.Errorf("no recipient found") 205 }