otp.c
changeset 55 0aaf56a96d21
child 56 a573346e6f7b
equal deleted inserted replaced
54:3d70f17a68b8 55:0aaf56a96d21
       
     1 #include <stdio.h>
       
     2 #include <stdint.h>
       
     3 #include <string.h>
       
     4 #include <time.h>
       
     5 #include "sha1.h"
       
     6 
       
     7 static int base32_decode(const char *src, const int srclen, uint8_t *dst, const int dstlen)
       
     8 {
       
     9     const int len = srclen == -1 ? strlen((const char *) src) : srclen;
       
    10     int retval = 0;
       
    11     uint32_t accum = 0;
       
    12     int shifter = 0;
       
    13     int i;
       
    14 
       
    15     for (i = 0; i < len; i++) {
       
    16         const uint8_t ch = (uint8_t) src[i];
       
    17         uint8_t val;
       
    18 
       
    19         if ((ch >= 'A') && (ch <= 'Z')) {
       
    20             val = ch - 'A';
       
    21         } else if ((ch >= '2') && (ch <= '7')) {
       
    22             val = (ch - '2') + 26;
       
    23         } else if (ch == '=') {
       
    24             val = 0;
       
    25 
       
    26         /* these are illegal in base32, but GAuth keys might have them. */
       
    27         } else if (ch == ' ') {
       
    28             continue;  /* skip these. */
       
    29         } else if ((ch >= 'a') && (ch <= 'z')) {
       
    30             val = ch - 'a'; /* treat like uppercase. */
       
    31 
       
    32         } else {
       
    33             return -1;  /* invalid string. */
       
    34         }
       
    35 
       
    36         accum = (accum << 5) | ((uint32_t) val);
       
    37         shifter += 5;
       
    38         if (shifter >= 8) {
       
    39             if (retval > dstlen) {
       
    40                 return -1;  /* dst too small */
       
    41             }
       
    42             dst[retval] = (uint8_t) ((accum >> (shifter - 8)) & 0xFF);
       
    43             retval++;
       
    44             shifter -= 8;
       
    45         }
       
    46     }
       
    47 
       
    48     if (shifter > 0) {
       
    49         if (retval > dstlen) {
       
    50             return -1;  /* dst too small */
       
    51         }
       
    52         dst[retval] = (uint8_t) (accum & 0xFF);
       
    53         retval++;
       
    54     }
       
    55 
       
    56     return retval;
       
    57 }
       
    58 
       
    59 static int totp(const char *base32_secret, char *dst, int dstlen)
       
    60 {
       
    61     uint8_t decoded[64];
       
    62     int decodedlen;
       
    63     uint64_t secs;
       
    64     uint8_t timebytes[8];
       
    65     unsigned char digest[SHA1_DIGEST_LENGTH];
       
    66     uint8_t *bytes;
       
    67     uint32_t val;
       
    68 
       
    69     decodedlen = base32_decode(base32_secret, -1, decoded, sizeof (decoded));
       
    70     if (decodedlen == -1) {
       
    71         return -1;
       
    72     }
       
    73 
       
    74     secs = ((uint64_t) time(NULL)) / 30;
       
    75     for (int i = 0; i < 8; i++) {
       
    76         timebytes[i] = (uint8_t) (secs >> ((7-i) * 8));
       
    77     }
       
    78 
       
    79     SHA1Hmac(decoded, decodedlen, timebytes, 8, digest);
       
    80 
       
    81     bytes = (uint8_t *) (digest + (digest[SHA1_DIGEST_LENGTH-1] & 0xF));
       
    82     val = (((uint32_t) bytes[0]) << 24) | (((uint32_t) bytes[1]) << 16) |
       
    83           (((uint32_t) bytes[2]) << 8) | (((uint32_t) bytes[3]));
       
    84     val &= 0x7FFFFFFF; /* drop most significant bit. */
       
    85     val %= 1000000;  /* make it six digits long. */
       
    86 
       
    87     snprintf(dst, dstlen, "%06u", (unsigned int) val);
       
    88     return 0;
       
    89 }
       
    90 
       
    91 int main(int argc, char **argv)
       
    92 {
       
    93     char result[16];
       
    94     int i;
       
    95     for (i = 1; i < argc; i++) {
       
    96         printf("%s: ", argv[i]);
       
    97         if (totp(argv[i], result, sizeof (result)) == -1) {
       
    98             printf("[FAILED!]");
       
    99         } else {
       
   100             printf("%s (valid for %d more seconds)", result, 30 - ((int) (time(NULL) % 30)));
       
   101         }
       
   102         printf("\n");
       
   103     }
       
   104     return 0;
       
   105 }
       
   106 
       
   107 /* end of otp.c ... */
       
   108