| 833 | } |
| 834 | |
| 835 | static int decrypt_file_to_stdout (const Key_file& key_file, const unsigned char* header, std::istream& in) |
| 836 | { |
| 837 | const unsigned char* nonce = header + 10; |
| 838 | uint32_t key_version = 0; // TODO: get the version from the file header |
| 839 | |
| 840 | const Key_file::Entry* key = key_file.get(key_version); |
| 841 | if (!key) { |
| 842 | std::clog << "git-crypt: error: key version " << key_version << " not available - please unlock with the latest version of the key." << std::endl; |
| 843 | return 1; |
| 844 | } |
| 845 | |
| 846 | Aes_ctr_decryptor aes(key->aes_key, nonce); |
| 847 | Hmac_sha1_state hmac(key->hmac_key, HMAC_KEY_LEN); |
| 848 | while (in) { |
| 849 | unsigned char buffer[1024]; |
| 850 | in.read(reinterpret_cast<char*>(buffer), sizeof(buffer)); |
| 851 | aes.process(buffer, buffer, in.gcount()); |
| 852 | hmac.add(buffer, in.gcount()); |
| 853 | std::cout.write(reinterpret_cast<char*>(buffer), in.gcount()); |
| 854 | } |
| 855 | |
| 856 | unsigned char digest[Hmac_sha1_state::LEN]; |
| 857 | hmac.get(digest); |
| 858 | if (!leakless_equals(digest, nonce, Aes_ctr_decryptor::NONCE_LEN)) { |
| 859 | std::clog << "git-crypt: error: encrypted file has been tampered with!" << std::endl; |
| 860 | // Although we've already written the tampered file to stdout, exiting |
| 861 | // with a non-zero status will tell git the file has not been filtered, |
| 862 | // so git will not replace it. |
| 863 | return 1; |
| 864 | } |
| 865 | |
| 866 | return 0; |
| 867 | } |
| 868 | |
| 869 | // Decrypt contents of stdin and write to stdout |
| 870 | int smudge (int argc, const char** argv) |