Encrypt walks over the tree and encrypts all values with the provided cipher, except those whose key ends with the UnencryptedSuffix specified on the Metadata struct, those not ending with EncryptedSuffix, if EncryptedSuffix is provided (by default it is not), those not matching EncryptedRegex, if E
(key []byte, cipher Cipher)
| 521 | // (all values if MACOnlyEncrypted is false, or only over values which end |
| 522 | // up encrypted if MACOnlyEncrypted is true). |
| 523 | func (tree Tree) Encrypt(key []byte, cipher Cipher) (string, error) { |
| 524 | audit.SubmitEvent(audit.EncryptEvent{ |
| 525 | File: tree.FilePath, |
| 526 | }) |
| 527 | hash := sha512.New() |
| 528 | if tree.Metadata.MACOnlyEncrypted { |
| 529 | // We initialize with known set of bytes so that a MAC with this setting |
| 530 | // enabled is always different from a MAC with this setting disabled. |
| 531 | hash.Write(MACOnlyEncryptedInitialization) |
| 532 | } |
| 533 | walk := func(branch TreeBranch) error { |
| 534 | _, err := branch.walkBranch(branch, make([]string, 0), make([][]string, 0), func(in interface{}, path []string, commentsStack [][]string) (interface{}, error) { |
| 535 | _, ok := in.(Comment) |
| 536 | encrypted := tree.shouldBeEncrypted(path, commentsStack, ok) |
| 537 | if !tree.Metadata.MACOnlyEncrypted || encrypted { |
| 538 | // Only add to MAC if not a comment |
| 539 | if !ok { |
| 540 | bytes, err := ToBytes(in) |
| 541 | if err != nil { |
| 542 | return nil, fmt.Errorf("Could not convert %s to bytes: %s", in, err) |
| 543 | } |
| 544 | hash.Write(bytes) |
| 545 | } |
| 546 | } |
| 547 | if encrypted { |
| 548 | var err error |
| 549 | pathString := strings.Join(path, ":") + ":" |
| 550 | in, err = cipher.Encrypt(in, key, pathString) |
| 551 | if err != nil { |
| 552 | return nil, fmt.Errorf("Could not encrypt value: %s", err) |
| 553 | } |
| 554 | if ok && tree.Metadata.UnencryptedCommentRegex != "" { |
| 555 | // If an encrypted comment matches tree.Metadata.UnencryptedCommentRegex, decryption will fail |
| 556 | // as the MAC does not match, and the commented value will not be decrypted. |
| 557 | // Note that cipher.Encrypt() returns a string, but we stored the result in an interface{} |
| 558 | // variable, so we have to cast it back. |
| 559 | matched, _ := regexp.Match(tree.Metadata.UnencryptedCommentRegex, []byte(in.(string))) |
| 560 | if matched { |
| 561 | return nil, fmt.Errorf("Encrypted comment %q matches UnencryptedCommentRegex! Make sure that UnencryptedCommentRegex cannot match an encrypted comment.", in) |
| 562 | } |
| 563 | } |
| 564 | } |
| 565 | return in, nil |
| 566 | }) |
| 567 | return err |
| 568 | } |
| 569 | |
| 570 | for _, branch := range tree.Branches { |
| 571 | err := walk(branch) |
| 572 | if err != nil { |
| 573 | return "", fmt.Errorf("Error walking tree: %s", err) |
| 574 | } |
| 575 | } |
| 576 | return fmt.Sprintf("%X", hash.Sum(nil)), nil |
| 577 | } |
| 578 | |
| 579 | // Decrypt walks over the tree and decrypts all values with the provided cipher, |
| 580 | // except those whose key ends with the UnencryptedSuffix specified on the Metadata struct, |