Update the GPL boilerplate with the new address of the FSF.
[freeradius.git] / src / modules / rlm_otp / otp_x99.c
1 /*
2  * otp_x99.c
3  * $Id$
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  * Copyright 2001,2002  Google, Inc.
20  * Copyright 2005 TRI-D Systems, Inc.
21  */
22
23 #include "otp.h"
24
25 #include <string.h>
26 #include <openssl/des.h>
27
28 static const char rcsid[] = "$Id$";
29
30
31 /*
32  * The ANSI X9.9 MAC algorithm is:
33  * 1. Perform a CBC mode DES encryption of the plaintext.  The last plaintext
34  *    block must be zero padded.
35  * 2. The MAC is the most significant 32 bits of the last cipherblock.
36  *
37  * Most tokens support a max of an 8 character challenge, but at least one
38  * (CRYPTOCard RB-1) supports performing the full CBC mode encryption
39  * of an arbitrary length challenge.  So we don't limit ourselves
40  * to just an ECB mode encryption.
41  *
42  * This routine returns the entire 64 bit last cipherblock, at least one sync
43  * mode needs this (and ANSI X9.9 states that the MAC can be 48, and 64 bit
44  * MACs should be supported).  Returns 0 on success, non-zero otherwise.
45  */
46 int
47 otp_x99_mac(const unsigned char *input, size_t len, unsigned char output[8],
48             const unsigned char keyblock[OTP_MAX_KEY_LEN],
49             const char *log_prefix)
50 {
51   des_key_schedule ks;
52   des_cblock ivec;
53   des_cblock l_output[OTP_MAX_CHALLENGE_LEN / sizeof(des_cblock)];
54   int rc;
55
56   /*
57    * Setup and verify the key.
58    * This may be a bit expensive to do every time, but it
59    * makes more sense for calling functions to deal with
60    * the key itself, rather than the schedule.  In practice,
61    * I don't think this will amount to much, but I haven't
62    * actually profiled it.
63    * TODO: store in card_info after generating
64    */
65   if ((rc = des_set_key_checked((const_des_cblock *) keyblock, ks)) != 0) {
66     otp_log(OTP_LOG_ERR, "%s: %s: otp_x99_mac: DES key %s",
67             log_prefix, __func__,
68             rc == -1 ? "has incorrect parity" : "is weak");
69     return -1;
70   }
71
72   (void) memset(ivec, 0, sizeof(ivec));
73   des_cbc_encrypt(input, (unsigned char *) l_output, len,
74                   ks, &ivec, DES_ENCRYPT);
75   (void) memcpy(output, l_output[(len - 1) / 8], 8);
76   return 0;
77 }