pkcs5.c
Go to the documentation of this file.
00001 /*
00002  * PKCS #5 (Password-based Encryption)
00003  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "crypto/crypto.h"
00019 #include "crypto/md5.h"
00020 #include "asn1.h"
00021 #include "pkcs5.h"
00022 
00023 
00024 struct pkcs5_params {
00025         enum pkcs5_alg {
00026                 PKCS5_ALG_UNKNOWN,
00027                 PKCS5_ALG_MD5_DES_CBC
00028         } alg;
00029         u8 salt[8];
00030         size_t salt_len;
00031         unsigned int iter_count;
00032 };
00033 
00034 
00035 enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
00036 {
00037         if (oid->len == 7 &&
00038             oid->oid[0] == 1 /* iso */ &&
00039             oid->oid[1] == 2 /* member-body */ &&
00040             oid->oid[2] == 840 /* us */ &&
00041             oid->oid[3] == 113549 /* rsadsi */ &&
00042             oid->oid[4] == 1 /* pkcs */ &&
00043             oid->oid[5] == 5 /* pkcs-5 */ &&
00044             oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
00045                 return PKCS5_ALG_MD5_DES_CBC;
00046 
00047         return PKCS5_ALG_UNKNOWN;
00048 }
00049 
00050 
00051 static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
00052                             struct pkcs5_params *params)
00053 {
00054         struct asn1_hdr hdr;
00055         const u8 *enc_alg_end, *pos, *end;
00056         struct asn1_oid oid;
00057         char obuf[80];
00058 
00059         /* AlgorithmIdentifier */
00060 
00061         enc_alg_end = enc_alg + enc_alg_len;
00062 
00063         os_memset(params, 0, sizeof(*params));
00064 
00065         if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
00066                 wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
00067                            "(algorithm)");
00068                 return -1;
00069         }
00070 
00071         asn1_oid_to_str(&oid, obuf, sizeof(obuf));
00072         wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
00073         params->alg = pkcs5_get_alg(&oid);
00074         if (params->alg == PKCS5_ALG_UNKNOWN) {
00075                 wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
00076                            "algorithm %s", obuf);
00077                 return -1;
00078         }
00079 
00080         /*
00081          * PKCS#5, Section 8
00082          * PBEParameter ::= SEQUENCE {
00083          *   salt OCTET STRING SIZE(8),
00084          *   iterationCount INTEGER }
00085          */
00086 
00087         if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
00088             hdr.class != ASN1_CLASS_UNIVERSAL ||
00089             hdr.tag != ASN1_TAG_SEQUENCE) {
00090                 wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
00091                            "(PBEParameter) - found class %d tag 0x%x",
00092                            hdr.class, hdr.tag);
00093                 return -1;
00094         }
00095         pos = hdr.payload;
00096         end = hdr.payload + hdr.length;
00097 
00098         /* salt OCTET STRING SIZE(8) */
00099         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
00100             hdr.class != ASN1_CLASS_UNIVERSAL ||
00101             hdr.tag != ASN1_TAG_OCTETSTRING ||
00102             hdr.length != 8) {
00103                 wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
00104                            "(salt) - found class %d tag 0x%x size %d",
00105                            hdr.class, hdr.tag, hdr.length);
00106                 return -1;
00107         }
00108         pos = hdr.payload + hdr.length;
00109         os_memcpy(params->salt, hdr.payload, hdr.length);
00110         params->salt_len = hdr.length;
00111         wpa_hexdump(MSG_DEBUG, "PKCS #5: salt",
00112                     params->salt, params->salt_len);
00113 
00114         /* iterationCount INTEGER */
00115         if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
00116             hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
00117                 wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
00118                            "class %d tag 0x%x", hdr.class, hdr.tag);
00119                 return -1;
00120         }
00121         if (hdr.length == 1)
00122                 params->iter_count = *hdr.payload;
00123         else if (hdr.length == 2)
00124                 params->iter_count = WPA_GET_BE16(hdr.payload);
00125         else if (hdr.length == 4)
00126                 params->iter_count = WPA_GET_BE32(hdr.payload);
00127         else {
00128                 wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value "
00129                             " (iterationCount)",
00130                             hdr.payload, hdr.length);
00131                 return -1;
00132         }
00133         wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
00134                    params->iter_count);
00135         if (params->iter_count == 0 || params->iter_count > 0xffff) {
00136                 wpa_printf(MSG_INFO, "PKCS #5: Unsupported "
00137                            "iterationCount=0x%x", params->iter_count);
00138                 return -1;
00139         }
00140 
00141         return 0;
00142 }
00143 
00144 
00145 static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
00146                                                 const char *passwd)
00147 {
00148         unsigned int i;
00149         u8 hash[MD5_MAC_LEN];
00150         const u8 *addr[2];
00151         size_t len[2];
00152 
00153         if (params->alg != PKCS5_ALG_MD5_DES_CBC)
00154                 return NULL;
00155 
00156         addr[0] = (const u8 *) passwd;
00157         len[0] = os_strlen(passwd);
00158         addr[1] = params->salt;
00159         len[1] = params->salt_len;
00160         if (md5_vector(2, addr, len, hash) < 0)
00161                 return NULL;
00162         addr[0] = hash;
00163         len[0] = MD5_MAC_LEN;
00164         for (i = 1; i < params->iter_count; i++) {
00165                 if (md5_vector(1, addr, len, hash) < 0)
00166                         return NULL;
00167         }
00168         /* TODO: DES key parity bits(?) */
00169         wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
00170         wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
00171 
00172         return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
00173 }
00174 
00175 
00176 u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
00177                    const u8 *enc_data, size_t enc_data_len,
00178                    const char *passwd, size_t *data_len)
00179 {
00180         struct crypto_cipher *ctx;
00181         u8 *eb, pad;
00182         struct pkcs5_params params;
00183         unsigned int i;
00184 
00185         if (pkcs5_get_params(enc_alg, enc_alg_len, &params) < 0) {
00186                 wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
00187                 return NULL;
00188         }
00189 
00190         ctx = pkcs5_crypto_init(&params, passwd);
00191         if (ctx == NULL) {
00192                 wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
00193                 return NULL;
00194         }
00195 
00196         /* PKCS #5, Section 7 - Decryption process */
00197         if (enc_data_len < 16 || enc_data_len % 8) {
00198                 wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
00199                            "%d", (int) enc_data_len);
00200                 crypto_cipher_deinit(ctx);
00201                 return NULL;
00202         }
00203 
00204         eb = os_malloc(enc_data_len);
00205         if (eb == NULL) {
00206                 crypto_cipher_deinit(ctx);
00207                 return NULL;
00208         }
00209 
00210         if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
00211                 wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
00212                 crypto_cipher_deinit(ctx);
00213                 os_free(eb);
00214                 return NULL;
00215         }
00216         crypto_cipher_deinit(ctx);
00217 
00218         pad = eb[enc_data_len - 1];
00219         if (pad > 8) {
00220                 wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
00221                 os_free(eb);
00222                 return NULL;
00223         }
00224         for (i = enc_data_len - pad; i < enc_data_len; i++) {
00225                 if (eb[i] != pad) {
00226                         wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
00227                                     eb + enc_data_len - pad, pad);
00228                         os_free(eb);
00229                         return NULL;
00230                 }
00231         }
00232 
00233         wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
00234                         eb, enc_data_len - pad);
00235 
00236         *data_len = enc_data_len - pad;
00237         return eb;
00238 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35