1 /*
2 * (C) 2006 Jack Lloyd (lloyd@randombit.net)
3 */
4
5 #include "vnccrack.h"
6 #include <cctype>
7 #include <fstream>
8
9 namespace {
10
get_nibble(char hex)11 unsigned char get_nibble(char hex)
12 {
13 if(std::isupper(hex))
14 return (hex - 'A') + 10; // upper case
15 else if(std::islower(hex))
16 return (hex - 'a') + 10; // lower case
17 else
18 return (hex - '0'); // digit
19 }
20
hex_decode(const char * in,int in_len)21 std::vector<unsigned char> hex_decode(const char* in, int in_len)
22 {
23 if(in_len % 2 != 0)
24 throw Exception("Hex strings must have even length");
25
26 std::vector<unsigned char> out(in_len / 2);
27
28 for(int j = 0; j != in_len; j += 2)
29 {
30 unsigned char nibble1 = get_nibble(in[j]);
31 unsigned char nibble2 = get_nibble(in[j+1]);
32 out[j/2] = (nibble1 << 4) | nibble2;
33 }
34
35 return out;
36 }
37
38 }
39
is_solved() const40 bool ChallengeResponse::is_solved() const
41 {
42 return !solution.empty();
43 }
44
solution_is() const45 std::string ChallengeResponse::solution_is() const
46 {
47 return solution;
48 }
49
to_string() const50 std::string ChallengeResponse::to_string() const
51 {
52 return string_rep;
53 }
54
test(const TrialPassword & pass)55 void ChallengeResponse::test(const TrialPassword& pass)
56 {
57 if(is_solved())
58 return;
59
60 DES_key_schedule des_ks = pass.key_schedule();
61
62 bool matched = true;
63
64 for(int j = 0; j != 16 && matched; j += 8)
65 {
66 unsigned char temp[8];
67
68 for(int k = 0; k != 8; k++)
69 temp[k] = challenge[j+k];
70
71 DES_ecb_encrypt(&temp, &temp, &des_ks, DES_ENCRYPT);
72
73 for(int k = 0; k != 8; k++)
74 if(temp[k] != response[j+k])
75 matched = false;
76 }
77
78 if(matched)
79 solution = pass.password();
80 }
81
ChallengeResponse(const std::string & line)82 ChallengeResponse::ChallengeResponse(const std::string& line) :
83 string_rep(line)
84 {
85 std::string hex;
86 for(std::size_t j = 0; j != line.size(); j++)
87 {
88 if(line[j] == '#') // skip comments
89 break;
90
91 if(std::isxdigit(line[j]))
92 hex += line[j];
93 }
94
95 if(hex.size() != 64)
96 throw Exception("Bad C/R input line " + line);
97
98 const char* hex_str = hex.c_str();
99
100 challenge = hex_decode(hex_str, 32);
101 response = hex_decode(hex_str + 32, 32);
102 }
103
test(const TrialPassword & pass,Report & report)104 void ChallengeResponses::test(const TrialPassword& pass, Report& report)
105 {
106 for(std::size_t j = 0; j != crpairs.size(); j++)
107 {
108 if(crpairs[j].is_solved())
109 continue;
110
111 crpairs[j].test(pass);
112
113 if(crpairs[j].is_solved())
114 report.solution(crpairs[j], pass.password());
115 }
116 }
117
ChallengeResponses(const std::string & filename)118 ChallengeResponses::ChallengeResponses(const std::string& filename)
119 {
120 std::ifstream in(filename.c_str());
121 if(!in)
122 throw Exception("Couldn't open C/R pair file " + filename);
123
124 while(in.good())
125 {
126 std::string line;
127 std::getline(in, line);
128
129 if(line == "" || line[0] == '#')
130 continue;
131
132 ChallengeResponse cr(line);
133 crpairs.push_back(cr);
134 }
135
136 if(crpairs.size() == 0)
137 throw Exception("No challenge/response pairs found");
138 }
139
count() const140 int ChallengeResponses::count() const
141 {
142 return crpairs.size();
143 }
144
all_solved() const145 bool ChallengeResponses::all_solved() const
146 {
147 for(std::size_t j = 0; j != crpairs.size(); j++)
148 if(!crpairs[j].is_solved())
149 return false;
150 return true;
151 }
152