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