]> git.earman.xyz Git - sensor-watch.git/commitdiff
Properly vendor TOTP-MCU temporarily
authorWesley Ellis <tahnok@gmail.com>
Wed, 24 Nov 2021 02:37:54 +0000 (21:37 -0500)
committerWesley Ellis <tahnok@gmail.com>
Wed, 24 Nov 2021 02:40:27 +0000 (21:40 -0500)
movement/lib/TOTP-MCU [deleted submodule]
movement/lib/TOTP-MCU/LICENSE [new file with mode: 0644]
movement/lib/TOTP-MCU/README.md [new file with mode: 0644]
movement/lib/TOTP-MCU/TOTP.c [new file with mode: 0644]
movement/lib/TOTP-MCU/TOTP.h [new file with mode: 0644]
movement/lib/TOTP-MCU/blink.c [new file with mode: 0644]
movement/lib/TOTP-MCU/sha1.c [new file with mode: 0644]
movement/lib/TOTP-MCU/sha1.h [new file with mode: 0644]

diff --git a/movement/lib/TOTP-MCU b/movement/lib/TOTP-MCU
deleted file mode 160000 (submodule)
index 646474a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 646474a8757e1fca490792e81082b2ad89b966a3
diff --git a/movement/lib/TOTP-MCU/LICENSE b/movement/lib/TOTP-MCU/LICENSE
new file mode 100644 (file)
index 0000000..6de4c0f
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Weravech
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/movement/lib/TOTP-MCU/README.md b/movement/lib/TOTP-MCU/README.md
new file mode 100644 (file)
index 0000000..df5ab96
--- /dev/null
@@ -0,0 +1,57 @@
+TOTP Pure C Library for ALL MCU
+====================
+
+Library to generate Time-based One-Time Passwords.
+
+Implements the Time-based One-Time Password algorithm specified in [RFC 6238](https://tools.ietf.org/html/rfc6238). 
+Supports different time steps and is compatible with tokens that use the same standard (including software ones, like the Google Authenticator app).
+
+Tested on MCUs: MSP430, RP2040
+
+Installation & usage:
+--------------------
+First include header to your file
+```
+#include <totp.h>
+```
+After included, define key ex. Key is ```MyLegoDoor```
+- Note: The format of hmacKey is array of hexadecimal bytes.
+- Most websites provide the key encoded in base32 - RFC3548/RFC4648, either upper or lower case. You can use [this site](https://cryptii.com/pipes/base32-to-hex) to convert the base32 string to hex (make sure you upcase it first if it's lowercase and remove all whitespaces).
+```
+uint8_t hmacKey[] = {0x4d, 0x79, 0x4c, 0x65, 0x67, 0x6f, 0x44, 0x6f, 0x6f, 0x72};               // Secret key
+```
+Instantiate the TOTP class by providing the secret hmacKey, the length of the hmacKey and the Timestep between codes.
+```
+TOTP(hmacKey, 10, 30);                                     // Secret key, Secret key length, Timestep (30s)
+```
+Use the ```getCodeFromTimestamp()``` function to get a TOTP from a unix epoch timestamp
+```
+uint32_t newCode = getCodeFromTimestamp(1557414000);       // Current timestamp since Unix epoch in seconds
+```
+Or ```getCodeFromTimeStruct()``` if you want to get a TOTP from a tm struct (Time Struct in C), 
+```
+struct tm datetime;
+datetime.tm_hour = 9;
+datetime.tm_min = 0;
+datetime.tm_sec = 0;
+datetime.tm_mday = 13;
+datetime.tm_mon = 5;
+datetime.tm_year = 2019;
+uint32_t newCode = getCodeFromTimeStruct(datetime);
+```
+
+If the provided unix timestamp isn't in UTC±0, use ```setTimezone()``` before ```getCodeFromTimestamp()``` or ```getCodeFromTimeStruct()``` to offset the time.
+
+```
+setTimezone(9);                                            // Set timezone +9 Japan
+```
+
+You can see an example in blink.c
+
+Thanks to:
+----------
+
+* Jose Damico, https://github.com/damico/ARDUINO-OATH-TOKEN
+* Peter Knight, https://github.com/Cathedrow/Cryptosuite
+* Maniacbug, https://github.com/maniacbug/Cryptosuite
+* lucadentella, https://github.com/lucadentella/TOTP-Arduino
diff --git a/movement/lib/TOTP-MCU/TOTP.c b/movement/lib/TOTP-MCU/TOTP.c
new file mode 100644 (file)
index 0000000..d977d06
--- /dev/null
@@ -0,0 +1,69 @@
+#include "TOTP.h"\r
+#include "sha1.h"\r
+\r
+uint8_t* _hmacKey;\r
+uint8_t _keyLength;\r
+uint8_t _timeZoneOffset;\r
+uint32_t _timeStep;\r
+\r
+// Init the library with the private key, its length and the timeStep duration\r
+void TOTP(uint8_t* hmacKey, uint8_t keyLength, uint32_t timeStep) {\r
+    _hmacKey = hmacKey;\r
+    _keyLength = keyLength;\r
+    _timeStep = timeStep;\r
+}\r
+\r
+void setTimezone(uint8_t timezone){\r
+    _timeZoneOffset = timezone;\r
+}\r
+\r
+uint32_t TimeStruct2Timestamp(struct tm time){\r
+    //time.tm_mon -= 1;\r
+    //time.tm_year -= 1900;\r
+    return mktime(&(time)) - (_timeZoneOffset * 3600) - 2208988800;\r
+}\r
+\r
+// Generate a code, using the timestamp provided\r
+uint32_t getCodeFromTimestamp(uint32_t timeStamp) {\r
+    uint32_t steps = timeStamp / _timeStep;\r
+    return getCodeFromSteps(steps);\r
+}\r
+\r
+// Generate a code, using the timestamp provided\r
+uint32_t getCodeFromTimeStruct(struct tm time) {\r
+    return getCodeFromTimestamp(TimeStruct2Timestamp(time));\r
+}\r
+\r
+// Generate a code, using the number of steps provided\r
+uint32_t getCodeFromSteps(uint32_t steps) {\r
+    // STEP 0, map the number of steps in a 8-bytes array (counter value)\r
+    uint8_t _byteArray[8];\r
+    _byteArray[0] = 0x00;\r
+    _byteArray[1] = 0x00;\r
+    _byteArray[2] = 0x00;\r
+    _byteArray[3] = 0x00;\r
+    _byteArray[4] = (uint8_t)((steps >> 24) & 0xFF);\r
+    _byteArray[5] = (uint8_t)((steps >> 16) & 0xFF);\r
+    _byteArray[6] = (uint8_t)((steps >> 8) & 0XFF);\r
+    _byteArray[7] = (uint8_t)((steps & 0XFF));\r
+\r
+    // STEP 1, get the HMAC-SHA1 hash from counter and key\r
+    initHmac(_hmacKey, _keyLength);\r
+    writeArray(_byteArray, 8);\r
+    uint8_t* _hash = resultHmac();\r
+\r
+    // STEP 2, apply dynamic truncation to obtain a 4-bytes string\r
+    uint32_t _truncatedHash = 0;\r
+    uint8_t _offset = _hash[20 - 1] & 0xF;\r
+    uint8_t j;\r
+    for (j = 0; j < 4; ++j) {\r
+        _truncatedHash <<= 8;\r
+        _truncatedHash  |= _hash[_offset + j];\r
+    }\r
+\r
+    // STEP 3, compute the OTP value\r
+    _truncatedHash &= 0x7FFFFFFF;    //Disabled\r
+    _truncatedHash %= 1000000;\r
+\r
+    return _truncatedHash;\r
+}\r
diff --git a/movement/lib/TOTP-MCU/TOTP.h b/movement/lib/TOTP-MCU/TOTP.h
new file mode 100644 (file)
index 0000000..13715f4
--- /dev/null
@@ -0,0 +1,8 @@
+#include <inttypes.h>\r
+#include "time.h"\r
+\r
+void TOTP(uint8_t* hmacKey, uint8_t keyLength, uint32_t timeStep);\r
+void setTimezone(uint8_t timezone);\r
+uint32_t getCodeFromTimestamp(uint32_t timeStamp);\r
+uint32_t getCodeFromTimeStruct(struct tm time);\r
+uint32_t getCodeFromSteps(uint32_t steps);\r
diff --git a/movement/lib/TOTP-MCU/blink.c b/movement/lib/TOTP-MCU/blink.c
new file mode 100644 (file)
index 0000000..9ec14ec
--- /dev/null
@@ -0,0 +1,39 @@
+#include <msp430.h>                            \r
+#include <totp.h>\r
+#include <stdint.h>\r
+\r
+/**\r
+ * blink.c\r
+ */\r
+void main(void)\r
+{\r
+       WDTCTL = WDTPW | WDTHOLD;               // stop watchdog timer\r
+       P1DIR |= 0x01;                                  // configure P1.0 as output\r
+\r
+       uint8_t hmacKey[] = {0x4d, 0x79, 0x4c, 0x65, 0x67, 0x6f, 0x44, 0x6f, 0x6f, 0x72};               // Secret key\r
+       TOTP(hmacKey, 10, 7200);                                                                        // Secret key, Key length, Timestep (7200s - 2hours)\r
+\r
+       setTimezone(9);                                                                                 // Set timezone\r
+       uint32_t newCode = getCodeFromTimestamp(1557414000);                                            // Timestamp Now\r
+\r
+       ///////////////// For struct tm //////////////////\r
+    // struct tm datetime;\r
+    // datetime.tm_hour = 9;\r
+    // datetime.tm_min = 0;\r
+    // datetime.tm_sec = 0;\r
+    // datetime.tm_mday = 13;\r
+    // datetime.tm_mon = 5;\r
+    // datetime.tm_year = 2019;\r
+       //  uint32_t newCode = getCodeFromTimeStruct(datetime);\r
+       ///////////////////////////////////////////////////\r
+\r
+       volatile unsigned int i;                // volatile to prevent optimization\r
+\r
+       while(1)\r
+       {\r
+           if (newCode == 0){          // 0 = INPUT HERE\r
+               P1OUT ^= 0x01;          // toggle P1.0\r
+           }\r
+               for(i=10000; i>0; i--);     // delay\r
+       }\r
+}\r
diff --git a/movement/lib/TOTP-MCU/sha1.c b/movement/lib/TOTP-MCU/sha1.c
new file mode 100644 (file)
index 0000000..07ad697
--- /dev/null
@@ -0,0 +1,155 @@
+#include <string.h>\r
+#include "sha1.h"\r
+\r
+#define SHA1_K0 0x5a827999\r
+#define SHA1_K20 0x6ed9eba1\r
+#define SHA1_K40 0x8f1bbcdc\r
+#define SHA1_K60 0xca62c1d6\r
+\r
+uint8_t sha1InitState[] = {\r
+  0x01,0x23,0x45,0x67, // H0\r
+  0x89,0xab,0xcd,0xef, // H1\r
+  0xfe,0xdc,0xba,0x98, // H2\r
+  0x76,0x54,0x32,0x10, // H3\r
+  0xf0,0xe1,0xd2,0xc3  // H4\r
+};\r
+\r
+void init(void) {\r
+  memcpy(state.b,sha1InitState,HASH_LENGTH);\r
+  byteCount = 0;\r
+  bufferOffset = 0;\r
+}\r
+\r
+uint32_t rol32(uint32_t number, uint8_t bits) {\r
+  return ((number << bits) | (uint32_t)(number >> (32-bits)));\r
+}\r
+\r
+void hashBlock() {\r
+  uint8_t i;\r
+  uint32_t a,b,c,d,e,t;\r
+\r
+  a=state.w[0];\r
+  b=state.w[1];\r
+  c=state.w[2];\r
+  d=state.w[3];\r
+  e=state.w[4];\r
+  for (i=0; i<80; i++) {\r
+    if (i>=16) {\r
+      t = buffer.w[(i+13)&15] ^ buffer.w[(i+8)&15] ^ buffer.w[(i+2)&15] ^ buffer.w[i&15];\r
+      buffer.w[i&15] = rol32(t,1);\r
+    }\r
+    if (i<20) {\r
+      t = (d ^ (b & (c ^ d))) + SHA1_K0;\r
+    } else if (i<40) {\r
+      t = (b ^ c ^ d) + SHA1_K20;\r
+    } else if (i<60) {\r
+      t = ((b & c) | (d & (b | c))) + SHA1_K40;\r
+    } else {\r
+      t = (b ^ c ^ d) + SHA1_K60;\r
+    }\r
+    t+=rol32(a,5) + e + buffer.w[i&15];\r
+    e=d;\r
+    d=c;\r
+    c=rol32(b,30);\r
+    b=a;\r
+    a=t;\r
+  }\r
+  state.w[0] += a;\r
+  state.w[1] += b;\r
+  state.w[2] += c;\r
+  state.w[3] += d;\r
+  state.w[4] += e;\r
+}\r
+\r
+void addUncounted(uint8_t data) {\r
+  buffer.b[bufferOffset ^ 3] = data;\r
+  bufferOffset++;\r
+  if (bufferOffset == BLOCK_LENGTH) {\r
+    hashBlock();\r
+    bufferOffset = 0;\r
+  }\r
+}\r
+\r
+void write(uint8_t data) {\r
+  ++byteCount;\r
+  addUncounted(data);\r
+\r
+  return;\r
+}\r
+\r
+void writeArray(uint8_t *buffer, uint8_t size){\r
+    while (size--) {\r
+        write(*buffer++);\r
+    }\r
+}\r
+\r
+void pad() {\r
+  // Implement SHA-1 padding (fips180-2 \81\985.1.1)\r
+\r
+  // Pad with 0x80 followed by 0x00 until the end of the block\r
+  addUncounted(0x80);\r
+  while (bufferOffset != 56) addUncounted(0x00);\r
+\r
+  // Append length in the last 8 bytes\r
+  addUncounted(0); // We're only using 32 bit lengths\r
+  addUncounted(0); // But SHA-1 supports 64 bit lengths\r
+  addUncounted(0); // So zero pad the top bits\r
+  addUncounted(byteCount >> 29); // Shifting to multiply by 8\r
+  addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as\r
+  addUncounted(byteCount >> 13); // byte.\r
+  addUncounted(byteCount >> 5);\r
+  addUncounted(byteCount << 3);\r
+}\r
+\r
+uint8_t* result(void) {\r
+  // Pad to complete the last block\r
+  pad();\r
+\r
+  // Swap byte order back\r
+  uint8_t i;\r
+  for (i=0; i<5; i++) {\r
+    uint32_t a,b;\r
+    a=state.w[i];\r
+    b=a<<24;\r
+    b|=(a<<8) & 0x00ff0000;\r
+    b|=(a>>8) & 0x0000ff00;\r
+    b|=a>>24;\r
+    state.w[i]=b;\r
+  }\r
+\r
+  // Return pointer to hash (20 characters)\r
+  return state.b;\r
+}\r
+\r
+#define HMAC_IPAD 0x36\r
+#define HMAC_OPAD 0x5c\r
+\r
+void initHmac(const uint8_t* key, uint8_t keyLength) {\r
+  uint8_t i;\r
+  memset(keyBuffer,0,BLOCK_LENGTH);\r
+  if (keyLength > BLOCK_LENGTH) {\r
+    // Hash long keys\r
+    init();\r
+    for (;keyLength--;) write(*key++);\r
+    memcpy(keyBuffer,result(),HASH_LENGTH);\r
+  } else {\r
+    // Block length keys are used as is\r
+    memcpy(keyBuffer,key,keyLength);\r
+  }\r
+  // Start inner hash\r
+  init();\r
+  for (i=0; i<BLOCK_LENGTH; i++) {\r
+    write(keyBuffer[i] ^ HMAC_IPAD);\r
+  }\r
+}\r
+\r
+uint8_t* resultHmac(void) {\r
+  uint8_t i;\r
+  // Complete inner hash\r
+  memcpy(innerHash,result(),HASH_LENGTH);\r
+  // Calculate outer hash\r
+  init();\r
+  for (i=0; i<BLOCK_LENGTH; i++) write(keyBuffer[i] ^ HMAC_OPAD);\r
+  for (i=0; i<HASH_LENGTH; i++) write(innerHash[i]);\r
+  return result();\r
+}\r
diff --git a/movement/lib/TOTP-MCU/sha1.h b/movement/lib/TOTP-MCU/sha1.h
new file mode 100644 (file)
index 0000000..2257e36
--- /dev/null
@@ -0,0 +1,25 @@
+#include <inttypes.h>\r
+\r
+#define HASH_LENGTH 20\r
+#define BLOCK_LENGTH 64\r
+\r
+union _buffer {\r
+  uint8_t b[BLOCK_LENGTH];\r
+  uint32_t w[BLOCK_LENGTH/4];\r
+} buffer;\r
+union _state {\r
+  uint8_t b[HASH_LENGTH];\r
+  uint32_t w[HASH_LENGTH/4];\r
+} state;\r
+\r
+uint8_t bufferOffset;\r
+uint32_t byteCount;\r
+uint8_t keyBuffer[BLOCK_LENGTH];\r
+uint8_t innerHash[HASH_LENGTH];\r
+\r
+void init(void);\r
+void initHmac(const uint8_t* secret, uint8_t secretLength);\r
+uint8_t* result(void);\r
+uint8_t* resultHmac(void);\r
+void write(uint8_t);\r
+void writeArray(uint8_t *buffer, uint8_t size);\r