func()

in pkg/container/seal/v1/unseal.go [38:138]


func (a *adapter) Unseal(container *containerv1.Container, identity *memguard.LockedBuffer) (*containerv1.Container, error) {
	// Check parameters
	if types.IsNil(container) {
		return nil, fmt.Errorf("unable to process nil container")
	}
	if types.IsNil(container.Headers) {
		return nil, fmt.Errorf("unable to process nil container headers")
	}
	if identity == nil {
		return nil, fmt.Errorf("unable to process without container key")
	}

	// Check headers
	if container.Headers.ContentType != containerSealedContentType {
		return nil, fmt.Errorf("unable to unseal container")
	}

	// Check ephemeral container public encryption key
	if len(container.Headers.EncryptionPublicKey) != publicKeySize {
		return nil, fmt.Errorf("invalid container public size")
	}
	var publicKey [publicKeySize]byte
	copy(publicKey[:], container.Headers.EncryptionPublicKey[:publicKeySize])

	// Decode private key
	privRaw, err := base64.RawURLEncoding.DecodeString(strings.TrimPrefix(identity.String(), PrivateKeyPrefix))
	if err != nil {
		return nil, fmt.Errorf("unable to decode private key: %w", err)
	}
	if len(privRaw) != privateKeySize {
		return nil, fmt.Errorf("invalid identity private key length")
	}
	var pk [privateKeySize]byte
	copy(pk[:], privRaw[:privateKeySize])

	// Precompute identifier
	derivedKey := deriveSharedKeyFromRecipient(&publicKey, &pk)

	// Try recipients
	payloadKey, err := tryRecipientKeys(derivedKey, container.Headers.Recipients)
	if err != nil {
		return nil, fmt.Errorf("unable to unseal container: error occurred during recipient key tests: %w", err)
	}

	// Check private key
	if len(payloadKey) != encryptionKeySize {
		return nil, fmt.Errorf("unable to unseal container: invalid encryption key size")
	}
	var encryptionKey [encryptionKeySize]byte
	copy(encryptionKey[:], payloadKey[:encryptionKeySize])

	// Prepare sig nonce
	var pubSigNonce [nonceSize]byte
	copy(pubSigNonce[:], "harp_container_psigk_box")

	// Decrypt signing public key
	containerSignKeyRaw, ok := secretbox.Open(nil, container.Headers.ContainerBox, &pubSigNonce, &encryptionKey)
	if !ok {
		return nil, fmt.Errorf("invalid container key")
	}
	if len(containerSignKeyRaw) != ed25519.PublicKeySize {
		return nil, fmt.Errorf("unable to unseal container: invalid signature key size")
	}

	// Compute headers hash
	headerHash, err := computeHeaderHash(container.Headers)
	if err != nil {
		return nil, fmt.Errorf("unable to compute header hash: %w", err)
	}

	// Extract payload nonce
	var payloadNonce [nonceSize]byte
	copy(payloadNonce[:], headerHash[:nonceSize])

	// Decrypt payload
	payloadRaw, ok := secretbox.Open(nil, container.Raw, &payloadNonce, &encryptionKey)
	if !ok || len(payloadRaw) < signatureSize {
		return nil, fmt.Errorf("invalid ciphered content")
	}

	// Extract signature / content
	detachedSig := payloadRaw[:signatureSize]
	content := payloadRaw[signatureSize:]

	// Prepare protected content
	protectedHash := computeProtectedHash(headerHash, content)

	// Validate signature
	if !ed25519.Verify(containerSignKeyRaw, protectedHash, detachedSig) {
		return nil, fmt.Errorf("invalid container signature")
	}

	// Unmarshal inner container
	out := &containerv1.Container{}
	if err := proto.Unmarshal(content, out); err != nil {
		return nil, fmt.Errorf("unable to unpack inner content: %w", err)
	}

	// No error
	return out, nil
}