git.fiddlerwoaroof.com
Browse code

(init)

Ed Langley authored on 21/02/2020 03:31:15
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,8 @@
1
+.idea
2
+.DS_Store
3
+GPATH
4
+GRTAGS
5
+GTAGS
6
+a.out*
7
+*~
8
+cmake-build-debug
0 9
new file mode 100644
... ...
@@ -0,0 +1,9 @@
1
+cmake_minimum_required(VERSION 3.7)
2
+project(totp_proto)
3
+
4
+set(CMAKE_CXX_STANDARD 14)
5
+
6
+set(SOURCE_FILES main.cpp)
7
+add_executable(totp_proto ${SOURCE_FILES})
8
+
9
+target_link_libraries(totp_proto libcryptopp.a)
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
+}