Browse code
(init)
Ed Langley authored on 21/02/2020 03:31:15
Showing 4 changed files
Showing 4 changed files
0 | 10 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,167 @@ |
1 |
+#include <cmath> |
|
2 |
+#include <ctime> |
|
3 |
+#include <functional> |
|
4 |
+#include <iomanip> |
|
5 |
+#include <iostream> |
|
6 |
+#include <unistd.h> |
|
7 |
+ |
|
8 |
+#include <cryptopp/base32.h> |
|
9 |
+#include <cryptopp/hex.h> |
|
10 |
+#include <cryptopp/hmac.h> |
|
11 |
+#include <cryptopp/osrng.h> |
|
12 |
+ |
|
13 |
+using namespace std; |
|
14 |
+ |
|
15 |
+// CLASSES |
|
16 |
+ |
|
17 |
+class OTPGenerator { |
|
18 |
+public: |
|
19 |
+ virtual unsigned long generate(const CryptoPP::SecByteBlock &key, const CryptoPP::Integer &input) const = 0; |
|
20 |
+}; |
|
21 |
+ |
|
22 |
+int ipow(int base, int exp) { |
|
23 |
+ int result = 1; |
|
24 |
+ while (exp) { |
|
25 |
+ if (exp & 1) |
|
26 |
+ result *= base; |
|
27 |
+ exp >>= 1; |
|
28 |
+ base *= base; |
|
29 |
+ } |
|
30 |
+ |
|
31 |
+ return result; |
|
32 |
+} |
|
33 |
+ |
|
34 |
+class HOTP : public OTPGenerator { |
|
35 |
+private: |
|
36 |
+ unsigned int code_digits; |
|
37 |
+ |
|
38 |
+ unsigned long bytesToInt(const string &bytes) const { |
|
39 |
+ unsigned long result = 0; |
|
40 |
+ auto byteCount = bytes.size() - 1; |
|
41 |
+ for (auto byte = bytes.cbegin(); byte < bytes.cend(); byte++, byteCount--) { |
|
42 |
+ const uint8_t val = static_cast<uint8_t>(*byte); |
|
43 |
+ result |= val << (byteCount * 8); |
|
44 |
+ } |
|
45 |
+ return result; |
|
46 |
+ } |
|
47 |
+ |
|
48 |
+ unsigned long truncate(const string &mac) const { |
|
49 |
+ uint8_t offset = static_cast<uint8_t >(mac[19]) & static_cast<uint8_t>(0x0f); |
|
50 |
+ string offsetBytes = mac.substr(offset, 4); |
|
51 |
+ return bytesToInt(offsetBytes) & 0x7fffffff; |
|
52 |
+ } |
|
53 |
+ |
|
54 |
+public: |
|
55 |
+ HOTP(unsigned int digits): |
|
56 |
+ code_digits(digits) |
|
57 |
+ {} |
|
58 |
+ |
|
59 |
+ virtual unsigned long generate(const CryptoPP::SecByteBlock &key, const CryptoPP::Integer &counter) const override { |
|
60 |
+ string mac; |
|
61 |
+ |
|
62 |
+ CryptoPP::SecByteBlock counter_bytes(8); |
|
63 |
+ // Do I know that 8 is sufficient here? . . . |
|
64 |
+ counter.Encode(counter_bytes.BytePtr(), 8, CryptoPP::Integer::UNSIGNED); |
|
65 |
+ |
|
66 |
+ CryptoPP::HMAC<CryptoPP::SHA1> hmac(key, key.size()); |
|
67 |
+ |
|
68 |
+ CryptoPP::StringSink *stringSink = new CryptoPP::StringSink(mac); |
|
69 |
+ CryptoPP::HashFilter *hashFilter = new CryptoPP::HashFilter(hmac, stringSink); |
|
70 |
+ CryptoPP::StringSource ss2(counter_bytes, counter_bytes.size(), true, hashFilter); |
|
71 |
+ |
|
72 |
+ unsigned long result = truncate(mac); |
|
73 |
+ |
|
74 |
+ result = result % ipow(10, code_digits); |
|
75 |
+ return result; |
|
76 |
+ } |
|
77 |
+ |
|
78 |
+}; |
|
79 |
+ |
|
80 |
+class TOTP : public HOTP { |
|
81 |
+private: |
|
82 |
+ unsigned int time_step_size; |
|
83 |
+ |
|
84 |
+ time_t time_step(const time_t time, const int step = 30) const { |
|
85 |
+ // Time is > 0 so division produces the result we want. |
|
86 |
+ return time / step; |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+public: |
|
90 |
+ TOTP(unsigned int step, unsigned int digits): |
|
91 |
+ time_step_size(step), HOTP(digits) |
|
92 |
+ {} |
|
93 |
+ |
|
94 |
+ virtual unsigned long generate(const CryptoPP::SecByteBlock &key, const CryptoPP::Integer &time) const override { |
|
95 |
+ CryptoPP::Integer current_step = time_step(time.ConvertToLong(), time_step_size); |
|
96 |
+ return HOTP::generate(key, current_step); |
|
97 |
+ } |
|
98 |
+}; |
|
99 |
+ |
|
100 |
+// Frontend |
|
101 |
+ |
|
102 |
+CryptoPP::SecByteBlock generate_key(unsigned int size) { |
|
103 |
+ CryptoPP::AutoSeededRandomPool prng; |
|
104 |
+ |
|
105 |
+ CryptoPP::SecByteBlock key(size); |
|
106 |
+ prng.GenerateBlock(key, key.size()); |
|
107 |
+ return key; |
|
108 |
+} |
|
109 |
+ |
|
110 |
+time_t get_time() { |
|
111 |
+ time_t theTime = time(0); |
|
112 |
+ if (theTime == static_cast<time_t>(-1)) { |
|
113 |
+ std::cerr << "time() failed..." << endl; |
|
114 |
+ } |
|
115 |
+ return theTime; |
|
116 |
+} |
|
117 |
+ |
|
118 |
+typedef std::function<std::string(const CryptoPP::SecByteBlock&)> byte_encoder; |
|
119 |
+typedef std::function<time_t()> time_cb; |
|
120 |
+ |
|
121 |
+std::string base32_encode(const CryptoPP::SecByteBlock string) { |
|
122 |
+ std::string encoded; |
|
123 |
+ |
|
124 |
+ CryptoPP::StringSink *stringSink = new CryptoPP::StringSink(encoded); |
|
125 |
+ CryptoPP::Base32Encoder *base32Encoder = new CryptoPP::Base32Encoder(stringSink); |
|
126 |
+ |
|
127 |
+ const byte ALPHABET[32+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; |
|
128 |
+ CryptoPP::AlgorithmParameters params = CryptoPP::MakeParameters(CryptoPP::Name::EncodingLookupArray(),(const byte *)ALPHABET); |
|
129 |
+ base32Encoder->IsolatedInitialize(params); |
|
130 |
+ |
|
131 |
+ |
|
132 |
+ CryptoPP::StringSource ss1(string, string.size(), true, base32Encoder); |
|
133 |
+ return encoded; |
|
134 |
+} |
|
135 |
+ |
|
136 |
+void deterministic_main( |
|
137 |
+ const CryptoPP::SecByteBlock& key, |
|
138 |
+ const time_t theTime, |
|
139 |
+ const byte_encoder key_encoder, |
|
140 |
+ const OTPGenerator& code_generator |
|
141 |
+) { |
|
142 |
+ try { |
|
143 |
+ std::cout << "key: " << std::setw(41) << key_encoder(key) << std::endl; |
|
144 |
+ |
|
145 |
+ unsigned long result = code_generator.generate(key, theTime); |
|
146 |
+ |
|
147 |
+ cout << setw(46) << setfill('-') << "-" << endl << setfill(' '); |
|
148 |
+ cout << "code: " << setw(34) << " " << setw(6) << setfill('0') << result << endl << setfill(' '); |
|
149 |
+ } catch (const CryptoPP::Exception &e) { |
|
150 |
+ std::cerr << e.what() << endl; |
|
151 |
+ exit(1); |
|
152 |
+ } |
|
153 |
+ |
|
154 |
+} |
|
155 |
+ |
|
156 |
+ |
|
157 |
+int main() { |
|
158 |
+ unsigned int digits = 6; |
|
159 |
+ unsigned int time_step = 30; |
|
160 |
+ unsigned int key_size = 16; |
|
161 |
+ CryptoPP::SecByteBlock key = generate_key(key_size); |
|
162 |
+ time_t theTime = get_time(); |
|
163 |
+ TOTP code_generator = TOTP(time_step, digits); |
|
164 |
+ |
|
165 |
+ deterministic_main(key, theTime, base32_encode, code_generator); |
|
166 |
+ return 0; |
|
167 |
+} |
0 | 168 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,76 @@ |
1 |
+#include <stdio.h> |
|
2 |
+#include <string> |
|
3 |
+#include <sstream> |
|
4 |
+#include <iomanip> |
|
5 |
+#include <iostream> |
|
6 |
+#include <string.h> |
|
7 |
+#include <time.h> |
|
8 |
+ |
|
9 |
+#include <openssl/hmac.h> |
|
10 |
+#include <openssl/evp.h> |
|
11 |
+ |
|
12 |
+namespace { |
|
13 |
+ // done |
|
14 |
+ unsigned long bytesToInt(const std::string &bytes) { |
|
15 |
+ unsigned long result = 0; |
|
16 |
+ auto byteCount = bytes.size() - 1; |
|
17 |
+ for (auto byte = bytes.cbegin(); byte < bytes.cend(); byte++, byteCount--) { |
|
18 |
+ const uint8_t val = static_cast<uint8_t>(*byte); |
|
19 |
+ result |= val << (byteCount * 8); |
|
20 |
+ } |
|
21 |
+ return result; |
|
22 |
+ } |
|
23 |
+ |
|
24 |
+ //done |
|
25 |
+ int ipow(int base, int exp) { |
|
26 |
+ int result = 1; |
|
27 |
+ while (exp) { |
|
28 |
+ if (exp & 1) { |
|
29 |
+ result *= base; |
|
30 |
+ } |
|
31 |
+ exp >>= 1; |
|
32 |
+ base *= base; |
|
33 |
+ } |
|
34 |
+ |
|
35 |
+ return result; |
|
36 |
+ } |
|
37 |
+ |
|
38 |
+ //done |
|
39 |
+ unsigned char *timeToBytes(unsigned long long time, unsigned char *data, size_t data_size) { |
|
40 |
+ for (int idx = data_size - 1; idx > -1; idx--) { |
|
41 |
+ unsigned char next_digit = time & 0xff; |
|
42 |
+ data[idx] = next_digit; |
|
43 |
+ time >>= 8; |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ return data; |
|
47 |
+ } |
|
48 |
+ |
|
49 |
+ //done |
|
50 |
+ unsigned long truncate(const std::string &mac) { |
|
51 |
+ uint8_t offset = static_cast<uint8_t >(mac[19]) & static_cast<uint8_t>(0x0f); |
|
52 |
+ std::string offsetBytes = mac.substr(offset, 4); |
|
53 |
+ return bytesToInt(offsetBytes) & 0x7fffffff; |
|
54 |
+ } |
|
55 |
+ |
|
56 |
+ std::string hotp(const std::string &key, const unsigned char *data, size_t data_size, const int digits=6) { |
|
57 |
+ } |
|
58 |
+ |
|
59 |
+ std::string generate_token(const std::string &key, const int digits=6) { |
|
60 |
+ //done |
|
61 |
+ time_t time_chunk = ::time(nullptr) / 30; |
|
62 |
+ |
|
63 |
+ unsigned char data[8] = {0,0,0,0,0,0,0,0}; |
|
64 |
+ timeToBytes(time_chunk, data, 8); |
|
65 |
+ |
|
66 |
+ return hotp(key, data, 8, digits); |
|
67 |
+ } |
|
68 |
+} |
|
69 |
+ |
|
70 |
+int main() |
|
71 |
+{ |
|
72 |
+ char key[5] = "\x00\x00\x00\x00"; |
|
73 |
+ std::cout << generate_token(std::string(key, 5)) << std::endl;; |
|
74 |
+ |
|
75 |
+ return 0; |
|
76 |
+} |