~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/modules/rlm_otp/crcalc.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Hampson
  • Date: 2006-01-15 13:34:13 UTC
  • mto: (3.1.3 dapper) (4.1.3 sid) (1.1.14 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060115133413-zo1dslttvdoalqym
Tags: upstream-1.1.0
ImportĀ upstreamĀ versionĀ 1.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * crcalc.c
 
3
 *
 
4
 *   This program is free software; you can redistribute it and/or modify
 
5
 *   it under the terms of the GNU General Public License as published by
 
6
 *   the Free Software Foundation; either version 2 of the License, or
 
7
 *   (at your option) any later version.
 
8
 *
 
9
 *   This program is distributed in the hope that it will be useful,
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *   GNU General Public License for more details.
 
13
 *
 
14
 *   You should have received a copy of the GNU General Public License
 
15
 *   along with this program; if not, write to the Free Software
 
16
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 *
 
18
 * Copyright 2001,2002 Google, Inc.
 
19
 */
 
20
 
 
21
#include <stdio.h>
 
22
#include <string.h>
 
23
#include <ctype.h>
 
24
#include <openssl/des.h>
 
25
 
 
26
/*
 
27
 * Convert the ASCII string representation of a DES key to raw octets.
 
28
 * keyblock is filled in.  Returns 0 on success, -1 otherwise.
 
29
 */
 
30
static
 
31
int string_to_keyblock(const char *s, des_cblock keyblock)
 
32
{
 
33
  int i;
 
34
 
 
35
  if (s == NULL || strlen(s) < 16)
 
36
    return -1;
 
37
 
 
38
  /*
 
39
   * We could just use sscanf, but we do this a lot, and have very
 
40
   * specific needs, and it's easy to implement, so let's go for it!
 
41
   */
 
42
  for (i = 0; i < 8; ++i) {
 
43
    unsigned int n[2];
 
44
 
 
45
    n[0] = *s++ - '0';
 
46
    n[1] = *s++ - '0';
 
47
    if (n[0] > 9)
 
48
      n[0] -= 'a' - '9' - 1;
 
49
    if (n[1] > 9)
 
50
      n[1] -= 'a' - '9' - 1;
 
51
 
 
52
    keyblock[i]  = n[0] << 4;
 
53
    keyblock[i] += n[1];
 
54
  }
 
55
  return 0;
 
56
}
 
57
 
 
58
 
 
59
/* Character maps for generic hex and vendor specific decimal modes */
 
60
static const char ascii_conversion[]  = "0123456789abcdef";
 
61
static const char cc_dec_conversion[] = "0123456789012345";
 
62
 
 
63
/*
 
64
 * Convert a DES keyblock to an ASCII string.
 
65
 * Fills in s, which must point to at least 17 bytes of space.
 
66
 * Note that each octet expands into 2 hex digits in ASCII (0xAA -> 0x4141);
 
67
 * add a NULL string terminator and you get the 17 byte requirement.
 
68
 */
 
69
static
 
70
void keyblock_to_string(char *s, const des_cblock keyblock,
 
71
                        const char conversion[17])
 
72
{
 
73
    int i;
 
74
 
 
75
  for (i = 0; i < 8; ++i) {
 
76
    unsigned n[2];
 
77
 
 
78
    n[0] = (keyblock[i] >> 4) & 0x0f;
 
79
    n[1] = keyblock[i] & 0x0f;
 
80
    s[2 * i + 0] = conversion[n[0]];
 
81
    s[2 * i + 1] = conversion[n[1]];
 
82
  }
 
83
  s[16] = '\0';
 
84
}
 
85
 
 
86
 
 
87
int
 
88
main(int argc, char *argv[])
 
89
{
 
90
  char ascii_key[17];
 
91
  char challenge[10], response[9], response_long[17];
 
92
  char buf[BUFSIZ];
 
93
  des_cblock keyblock;
 
94
  des_key_schedule ks;
 
95
  char *p;
 
96
  int i, rc;
 
97
 
 
98
  memset(ascii_key, 0, sizeof(ascii_key));
 
99
 
 
100
  /* get the key */
 
101
  fprintf(stdout, "Enter a DES key as 16 hex digits (spaces allowed): ");
 
102
  fgets(buf, sizeof(buf), stdin);
 
103
  buf[strlen(buf) - 1] = '\0'; /* strip '\n' */
 
104
  p = buf;
 
105
 
 
106
  /* setup key */
 
107
  if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
 
108
    p += 2;
 
109
  i = 0;
 
110
  while (*p) {
 
111
    if (*p == ' ') {
 
112
      p++;
 
113
      continue;
 
114
    }
 
115
    if (*p < '0' || *p > '9') {
 
116
      if (*p < 'a' || *p > 'f') {
 
117
        if (*p < 'A' || *p > 'F') {
 
118
          fprintf(stderr, "bad key\n");
 
119
          exit(1);
 
120
        }
 
121
      }
 
122
    }
 
123
    if (i > 15) {
 
124
      fprintf(stderr, "key too long\n");
 
125
      exit(1);
 
126
    }
 
127
    ascii_key[i++] = tolower((int) *p++);
 
128
  }
 
129
  if (strlen(ascii_key) < 16) {
 
130
    fprintf(stderr, "key too short\n");
 
131
    exit(1);
 
132
  }
 
133
  string_to_keyblock(ascii_key, keyblock);
 
134
 
 
135
  /* verify the key. */
 
136
key_verify:
 
137
  if ((rc = des_set_key_checked(&keyblock, ks)) != 0) {
 
138
    fprintf(stderr, "key %s\n",
 
139
            rc == -1 ? "has incorrect parity" : "is weak");
 
140
    if (rc == -1) {
 
141
      des_set_odd_parity(&keyblock);
 
142
      goto key_verify;
 
143
    } else {
 
144
      exit(1);
 
145
    }
 
146
  }
 
147
 
 
148
  fprintf(stdout, "Enter the challenge: ");
 
149
  fgets(challenge, sizeof(challenge), stdin);
 
150
  challenge[strlen(challenge) - 1] = '\0'; /* strip '\n' */
 
151
  /* encrypt null block if no challenge */
 
152
 
 
153
  /*
 
154
   * Calculate the response.  The algorithm is:
 
155
   * 1. Convert the challenge to ASCII bytes (eg "12345" -> 0x3132333435).
 
156
   * 2. Pad LSB of a 64-bit block w/ 0 bytes if challenge < 8 bytes (digits).
 
157
   * 3. Encrypt w/ DES (whose block size is 64 bits).
 
158
   * 4. Convert the most significant 32 bits of the ciphertext
 
159
   *    to 8 hex digits as a string (eg 0x1234567f -> "1234567f").
 
160
   */
 
161
  {
 
162
    des_cblock input, output;
 
163
 
 
164
    /* Step 1, 2 (conversion is already done, just copy and pad) */
 
165
    (void) memset(input, 0, sizeof(input));
 
166
    (void) memcpy(input, challenge, strlen(challenge));
 
167
 
 
168
    /* Step 3 */
 
169
    des_ecb_encrypt(&input, &output, ks, 1);
 
170
 
 
171
    /* Step 4, 5 */
 
172
    keyblock_to_string(response_long, output, ascii_conversion);
 
173
    (void) memcpy(response, response_long, 8);
 
174
    response[8] = '\0';
 
175
    memcpy(challenge, output, 8);
 
176
    challenge[8] = '\0';
 
177
  }
 
178
 
 
179
  /* calculate the next challenge for cryptocard */
 
180
  for (i = 0; i < 8; ++i) {
 
181
    challenge[i] &= 0x0f;
 
182
    if (challenge[i] > 9)
 
183
      challenge[i] -= 10;
 
184
    challenge[i] |= 0x30;
 
185
  }
 
186
 
 
187
  fprintf(stdout, "response is %s [%s]\n", response, &response_long[8]);
 
188
  fprintf(stdout, "next challenge is %s\n", challenge);
 
189
  exit(0);
 
190
}