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;
50
n[1] -= 'a' - '9' - 1;
52
keyblock[i] = n[0] << 4;
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";
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.
70
void keyblock_to_string(char *s, const des_cblock keyblock,
71
const char conversion[17])
75
for (i = 0; i < 8; ++i) {
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]];
88
main(int argc, char *argv[])
91
char challenge[10], response[9], response_long[17];
98
memset(ascii_key, 0, sizeof(ascii_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' */
107
if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
115
if (*p < '0' || *p > '9') {
116
if (*p < 'a' || *p > 'f') {
117
if (*p < 'A' || *p > 'F') {
118
fprintf(stderr, "bad key\n");
124
fprintf(stderr, "key too long\n");
127
ascii_key[i++] = tolower((int) *p++);
129
if (strlen(ascii_key) < 16) {
130
fprintf(stderr, "key too short\n");
133
string_to_keyblock(ascii_key, keyblock);
135
/* verify the key. */
137
if ((rc = des_set_key_checked(&keyblock, ks)) != 0) {
138
fprintf(stderr, "key %s\n",
139
rc == -1 ? "has incorrect parity" : "is weak");
141
des_set_odd_parity(&keyblock);
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 */
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").
162
des_cblock input, output;
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));
169
des_ecb_encrypt(&input, &output, ks, 1);
172
keyblock_to_string(response_long, output, ascii_conversion);
173
(void) memcpy(response, response_long, 8);
175
memcpy(challenge, output, 8);
179
/* calculate the next challenge for cryptocard */
180
for (i = 0; i < 8; ++i) {
181
challenge[i] &= 0x0f;
182
if (challenge[i] > 9)
184
challenge[i] |= 0x30;
187
fprintf(stdout, "response is %s [%s]\n", response, &response_long[8]);
188
fprintf(stdout, "next challenge is %s\n", challenge);