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.
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.
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
18
* Copyright 2001,2002 Google, Inc.
24
#include <openssl/des.h>
27
* Convert the ASCII string representation of a DES key to raw octets.
28
* keyblock is filled in. Returns 0 on success, -1 otherwise.
31
int string_to_keyblock(const char *s, des_cblock keyblock)
35
if (s == NULL || strlen(s) < 16)
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!
42
for (i = 0; i < 8; ++i) {
48
n[0] -= 'a' - '9' - 1;
51
n[1] -= 'a' - '9' - 1;
54
keyblock[i] = n[0] << 4;
61
/* Character maps for generic hex and vendor specific decimal modes */
62
static const char ascii_conversion[] = "0123456789abcdef";
63
static const char cc_dec_conversion[] = "0123456789012345";
66
* Convert a DES keyblock to an ASCII string.
67
* Fills in s, which must point to at least 17 bytes of space.
68
* Note that each octet expands into 2 hex digits in ASCII (0xAA -> 0x4141);
69
* add a NULL string terminator and you get the 17 byte requirement.
72
void keyblock_to_string(char *s, const des_cblock keyblock,
73
const char conversion[17])
77
for (i = 0; i < 8; ++i) {
80
n[0] = (keyblock[i] >> 4) & 0x0f;
81
n[1] = keyblock[i] & 0x0f;
82
s[2 * i + 0] = conversion[n[0]];
83
s[2 * i + 1] = conversion[n[1]];
90
main(int argc, char *argv[])
94
char challenge[10], response[9], response_long[17];
101
memset(ascii_key, 0, sizeof(ascii_key));
104
fprintf(stdout, "Enter a DES key as 16 hex digits (spaces allowed): ");
105
fgets(buf, sizeof(buf), stdin);
106
buf[strlen(buf) - 1] = '\0'; /* strip '\n' */
110
if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
118
if (*p < '0' || *p > '9') {
119
if (*p < 'a' || *p > 'f') {
120
if (*p < 'A' || *p > 'F') {
121
fprintf(stderr, "bad key\n");
127
fprintf(stderr, "key too long\n");
130
ascii_key[i++] = tolower((int) *p++);
132
if (strlen(ascii_key) < 16) {
133
fprintf(stderr, "key too short\n");
136
string_to_keyblock(ascii_key, keyblock);
138
/* verify the key. */
140
if ((rc = des_set_key_checked(&keyblock, ks)) != 0) {
141
fprintf(stderr, "key %s\n",
142
rc == -1 ? "has incorrect parity" : "is weak");
144
des_set_odd_parity(&keyblock);
152
fprintf(stdout, "Enter the challenge: ");
153
fgets(challenge, sizeof(challenge), stdin);
154
challenge[strlen(challenge) - 1] = '\0'; /* strip '\n' */
155
/* encrypt null block if no challenge */
158
* Calculate the response. The algorithm is:
159
* 1. Convert the challenge to ASCII bytes (eg "12345" -> 0x3132333435).
160
* 2. Pad LSB of a 64-bit block w/ 0 bytes if challenge < 8 bytes (digits).
161
* 3. Encrypt w/ DES (whose block size is 64 bits).
162
* 4. Convert the most significant 32 bits of the ciphertext
163
* to 8 hex digits as a string (eg 0x1234567f -> "1234567f").
166
des_cblock input, output;
168
/* Step 1, 2 (conversion is already done, just copy and pad) */
169
(void) memset(input, 0, sizeof(input));
170
(void) memcpy(input, challenge, strlen(challenge));
173
des_ecb_encrypt(&input, &output, ks, 1);
176
keyblock_to_string(response_long, output, ascii_conversion);
177
(void) memcpy(response, response_long, 8);
179
memcpy(challenge, output, 8);
183
/* calculate the next challenge for cryptocard */
184
for (i = 0; i < 8; ++i) {
185
challenge[i] &= 0x0f;
186
if (challenge[i] > 9)
188
challenge[i] |= 0x30;
191
fprintf(stdout, "response is %s [%s]\n", response, &response_long[8]);
192
fprintf(stdout, "next challenge is %s\n", challenge);