📄 rsa_dec.cpp
字号:
/*Decrypt (and verify) an encrypted RSA private key. Then use that key to decrypta message. This program can decrypt messages generated by rsa_enc, and uses thesame key format as that generated by rsa_kgen.Written by Jack Lloyd (lloyd@randombit.net), June 3-5, 2002This file is in the public domain*/#include <iostream>#include <iomanip>#include <fstream>#include <cstdlib>#include <string>#include <botan/filters.h>#include <botan/look_pk.h>#include <botan/lookup.h>#include <botan/rsa.h>#include <botan/cbc.h>#include <botan/pgp_s2k.h>using namespace Botan;using namespace std;SecureVector<byte> b64_decode(const std::string&);SymmetricKey derive_key(const std::string&, const SymmetricKey&, u32bit);BigInt pop_bigint(Pipe&);const std::string SUFFIX = ".enc";int main(int argc, char* argv[]) { try { if(argc != 4) { cout << "Usage: rsa_dec keyfile messagefile passphrase" << endl; return 1; } ifstream keyfile(argv[1]); if(!keyfile) { cout << "Couldn't read the key file." << endl; return 1; } LibraryInitializer init; std::string salt_str, mac_str; std::getline(keyfile, salt_str); std::getline(keyfile, mac_str); // rest of keyfile should be the encrypted key OpenPGP_S2K s2k("SHA-1", 8192); s2k.change_salt(b64_decode(salt_str)); std::string passphrase(argv[3]); SymmetricKey cast_key = s2k.derive_key("CAST" + passphrase, 16); BlockCipherModeIV iv = s2k.derive_key("IV" + passphrase, 8); SymmetricKey mac_key = s2k.derive_key("MAC" + passphrase, 16); // we keep a reference around so we can reset the keys later Keyed_Filter *cast, *hmac; Pipe pipe(new Base64_Decoder, cast = new CBC_Decryption("CAST-128", "PKCS7", cast_key, iv), new Fork( 0, new Chain( hmac = new MAC_Filter("HMAC(SHA-1)", mac_key, 12), new Base64_Encoder ) ) ); try { pipe.start_msg(); keyfile >> pipe; pipe.end_msg(); } catch(Decoding_Error) { std::cout << "Bad decrypt of key file (bad passphrase?)\n"; return 1; } std::string our_mac = pipe.read_all_as_string(1); /* 99% of the time, the PKCS7 padding code will detect a bad passphrase, so really, the MAC isn't too useful, but whatever */ if(our_mac != mac_str) { std::cout << "MACs in keyfile failed to verify (bad passphrase?)\n"; return 1; } BigInt e = pop_bigint(pipe); BigInt p = pop_bigint(pipe); BigInt q = pop_bigint(pipe); RSA_PrivateKey rsakey(p, q, e); ifstream message(argv[2]); if(!message) { cout << "Couldn't read the message file." << endl; return 1; } std::string outfile(argv[2]); outfile = outfile.replace(outfile.find(SUFFIX), SUFFIX.length(), ""); ofstream plaintext(outfile.c_str()); if(!plaintext) { cout << "Couldn't write the plaintext to " << outfile << endl; return 1; } std::string enc_masterkey_str; std::getline(message, enc_masterkey_str); SecureVector<byte> enc_masterkey = b64_decode(enc_masterkey_str); PK_Decryptor decryptor(rsakey, "EME1(SHA-1)"); SecureVector<byte> masterkey = decryptor.decrypt(enc_masterkey); cast->reset_key(derive_key("CAST", masterkey, 16)); cast->reset_iv(derive_key("IV", masterkey, 8)); hmac->reset_key(derive_key("MAC", masterkey, 16)); std::getline(message, mac_str); pipe.start_msg(); message >> pipe; pipe.end_msg(); // Don't mind this. It's just some error checking for the garbage collection // stuff in Pipe. It doesn't need to be here in a normal program. if(pipe.remaining(0) || pipe.remaining(1)) throw Exception("pipe(0,1) not empty. Please email lloyd@randombit.net"); our_mac = pipe.read_all_as_string(3); if(our_mac != mac_str) std::cerr << "WARNING: MAC in message failed to verify\n"; plaintext << pipe.read_all_as_string(2); } catch(Exception& e) { cout << "Exception caught: " << e.what() << endl; } catch(exception& e) { cout << "Standard library exception caught: " << e.what() << endl; } catch(...) { cout << "Unknown exception caught." << endl; } return 0; }SecureVector<byte> b64_decode(const std::string& in) { Botan::Pipe pipe(new Botan::Base64_Decoder); pipe.start_msg(); pipe.write(in); pipe.end_msg(); return pipe.read_all(); }/* 4 bytes for the length is completely excessive. Hell, 1 byte will handle it most of the time (up to 2K bits), and 2 bytes is plenty for anything. Whatever.*/BigInt pop_bigint(Pipe& pipe) { byte len[4]; if(pipe.remaining() < 4) throw Exception("pop_bigint: Not enough bytes left (invalid file?)"); pipe.read(len, 4); u32bit length = make_u32bit(len[0], len[1], len[2], len[3]); if(pipe.remaining() < length) throw Exception("pop_bigint: Not enough bytes left (invalid file?)"); byte* buf = new byte[length]; pipe.read(buf, length); BigInt n(buf, length); delete[] buf; return n; }SymmetricKey derive_key(const std::string& param, const SymmetricKey& masterkey, u32bit outputlength) { if(outputlength > 16) throw Exception("Can't derive a key longer than 16 bytes with MD5"); HashFunction* md5 = get_hash("MD5"); md5->update(param); md5->update(masterkey, masterkey.length()); SecureVector<byte> hash = md5->final(); delete md5; return SymmetricKey(hash, outputlength); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -